Initial commit - cloned the Svelte todo's app with google login enabled as a starting point. This system will initially be used to let the chrome extension for students report which computers are used by which students and when.

This commit is contained in:
2021-09-16 07:26:57 -07:00
commit 08ec0543ca
29 changed files with 2477 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
private/settings.json

5
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

13
.idea/AvusdMeteor.iml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
<excludeFolder url="file://$MODULE_DIR$/.meteor/local" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/jsLibraryMappings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Meteor project library" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/AvusdMeteor.iml" filepath="$PROJECT_DIR$/.idea/AvusdMeteor.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,19 @@
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.
notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package
1.7-split-underscore-from-meteor-base
1.8.3-split-jquery-from-blaze

1
.meteor/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
local

7
.meteor/.id Normal file
View File

@@ -0,0 +1,7 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
ou78pym2e7kf.kuc1f56r19il

29
.meteor/packages Normal file
View File

@@ -0,0 +1,29 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base@1.4.0 # Packages every Meteor app needs to have
mobile-experience@1.1.0 # Packages for a great mobile UX
mongo@1.10.1 # The database Meteor supports right now
jquery # Wrapper package for npm-installed jquery
reactive-var@1.0.11 # Reactive variable for tracker
tracker@1.2.0 # Meteor's client-side reactive programming library
standard-minifier-css@1.7.1 # CSS minifier run for production mode
standard-minifier-js@2.6.0 # JS minifier run for production mode
es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers
ecmascript@0.14.4 # Enable ECMAScript2015+ syntax in app code
typescript@4.1.2 # Enable TypeScript syntax in .ts and .tsx modules
shell-server@0.5.0 # Server-side component of the `meteor shell` command
svelte:compiler
rdb:svelte-meteor-data
static-html
accounts-ui
accounts-password@1.6.3
svelte:blaze-integration
meteortesting:mocha
accounts-google
service-configuration

2
.meteor/platforms Normal file
View File

@@ -0,0 +1,2 @@
server
browser

1
.meteor/release Normal file
View File

@@ -0,0 +1 @@
METEOR@1.12

104
.meteor/versions Normal file
View File

@@ -0,0 +1,104 @@
accounts-base@1.7.1
accounts-google@1.3.3
accounts-oauth@1.2.0
accounts-password@1.6.3
accounts-ui@1.3.2
accounts-ui-unstyled@1.4.3
allow-deny@1.1.0
autoupdate@1.6.0
babel-compiler@7.5.4
babel-runtime@1.5.0
base64@1.0.12
binary-heap@1.0.11
blaze@2.3.4
blaze-tools@1.0.10
boilerplate-generator@1.7.1
caching-compiler@1.2.2
caching-html-compiler@1.1.3
callback-hook@1.3.0
check@1.3.1
ddp@1.4.0
ddp-client@2.3.3
ddp-common@1.4.0
ddp-rate-limiter@1.0.9
ddp-server@2.3.2
deps@1.0.12
diff-sequence@1.1.1
dynamic-import@0.5.4
ecmascript@0.14.4
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.11.0
ecmascript-runtime-server@0.10.0
ejson@1.1.1
email@2.0.0
es5-shim@4.8.0
fetch@0.1.1
geojson-utils@1.0.10
google-oauth@1.3.0
hot-code-push@1.0.4
html-tools@1.0.11
htmljs@1.0.11
http@1.4.2
id-map@1.1.0
inter-process-messaging@0.1.1
jquery@3.0.0
launch-screen@1.2.0
less@3.0.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.20
meteor@1.9.3
meteor-base@1.4.0
meteortesting:browser-tests@1.3.4
meteortesting:mocha@2.0.1
meteortesting:mocha-core@8.1.2
minifier-css@1.5.3
minifier-js@2.6.0
minimongo@1.6.1
mobile-experience@1.1.0
mobile-status-bar@1.1.0
modern-browsers@0.1.5
modules@0.15.0
modules-runtime@0.12.0
mongo@1.10.1
mongo-decimal@0.1.2
mongo-dev-server@1.1.0
mongo-id@1.0.7
npm-bcrypt@0.9.3
npm-mongo@3.8.1
oauth@1.3.2
oauth2@1.3.0
observe-sequence@1.0.16
ordered-dict@1.1.0
promise@0.11.2
random@1.2.0
rate-limit@1.0.9
rdb:svelte-meteor-data@0.3.0
reactive-dict@1.3.0
reactive-var@1.0.11
reload@1.3.1
retry@1.1.0
routepolicy@1.1.0
service-configuration@1.0.11
session@1.2.0
sha@1.0.9
shell-server@0.5.0
socket-stream-client@0.3.1
spacebars@1.0.15
spacebars-compiler@1.1.3
srp@1.1.0
standard-minifier-css@1.7.1
standard-minifier-js@2.6.0
static-html@1.2.2
svelte:blaze-integration@0.4.0
svelte:compiler@3.27.0
templating@1.3.2
templating-compiler@1.3.3
templating-runtime@1.3.2
templating-tools@1.1.2
tracker@1.2.0
typescript@4.1.2
underscore@1.0.10
url@1.3.1
webapp@1.9.1
webapp-hashing@1.0.9

126
client/main.css Normal file
View File

@@ -0,0 +1,126 @@
/* CSS declarations go here */
body {
padding: 10px;
font-family: sans-serif;
background-color: #315481;
background-image: linear-gradient(to bottom, #315481, #918e82 100%);
background-attachment: fixed;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 0;
margin: 0;
font-size: 14px;
}
.container {
max-width: 600px;
margin: 0 auto;
min-height: 100%;
background: white;
}
header {
background: #d2edf4;
background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
padding: 20px 15px 15px 15px;
position: relative;
}
#login-buttons {
display: block;
}
h1 {
font-size: 1.5em;
margin: 0;
margin-bottom: 10px;
display: inline-block;
margin-right: 1em;
}
form {
margin-top: 10px;
margin-bottom: -10px;
position: relative;
}
.new-task input {
box-sizing: border-box;
padding: 10px 0;
background: transparent;
border: none;
width: 100%;
padding-right: 80px;
font-size: 1em;
}
.new-task input:focus {
outline: 0;
}
ul {
margin: 0;
padding: 0;
background: white;
}
.delete {
float: right;
font-weight: bold;
background: none;
font-size: 1em;
border: none;
position: relative;
}
li {
position: relative;
list-style: none;
padding: 15px;
border-bottom: #eee solid 1px;
}
li .text {
margin-left: 10px;
}
li.checked {
color: #888;
}
li.checked .text {
text-decoration: line-through;
}
li.private {
background: #eee;
border-color: #ddd;
}
header .hide-completed {
float: right;
}
.toggle-private {
margin-left: 5px;
}
@media (max-width: 600px) {
li {
padding: 12px 15px;
}
.search {
width: 150px;
clear: both;
}
.new-task input {
padding-bottom: 5px;
}
}
/*# sourceMappingURL=main.css.map */

1
client/main.css.map Normal file
View File

@@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["main.sass"],"names":[],"mappings":"AAAA;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAED;EACC;EACA;EACA;EACA;;;AAED;EACC;EACA;EACA;EACA;;;AAED;EACC;;;AAED;EACC;EACA;EACA;EACA;EACA;;;AAED;EACC;EACA;EACA;;;AAED;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAED;EACC;;;AAED;EACC;EACA;EACA;;;AAED;EACC;EACA;EACA;EACA;EACA;EACA;;;AAED;EACC;EACA;EACA;EACA;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;EACA;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;IACC;;;EAED;IACC;IACA;;;EAED;IACC","file":"main.css"}

8
client/main.html Normal file
View File

@@ -0,0 +1,8 @@
<head>
<title>Todo List</title>
</head>
<body>
<div id="app"></div>
</body>

127
client/main.js Normal file
View File

@@ -0,0 +1,127 @@
import {Meteor} from 'meteor/meteor';
import App from '../imports/ui/App.svelte';
import '../imports/startup/accounts-config.js';
import Phaser from 'phaser';
Meteor.startup(() => {
new App({
target: document.getElementById('app')
});
class playGame extends Phaser.Scene {
constructor() {
super("PlayGame");
}
create() {
// graphic object used to draw walls
this.wallGraphics = this.add.graphics();
this.wallGraphics.lineStyle(1, 0x00ff00);
// graphic object used to draw rays of light
this.lightGraphics = this.add.graphics();
// array with all polygons in game
this.polygons = [];
// add random boxes
for(let i = 0; i < gameOptions.boxes; i ++){
this.addRandomBox();
}
// walls around game perimeter
this.polygons.push([[-1, -1], [game.config.width + 1, -1], [game.config.width + 1, game.config.height+1], [-1, game.config.height + 1]]);
// listener for input movement
this.input.on("pointermove", this.renderLight, this);
}
addRandomBox() {
// use a do...while statement because there can't be intersecting polygons
do {
// random x and y coordinates, width and height
var startX = Phaser.Math.Between(10, game.config.width - 10 - gameOptions.sizeRange.max);
var startY = Phaser.Math.Between(10, game.config.height - 10 - gameOptions.sizeRange.max);
var width = Phaser.Math.Between(gameOptions.sizeRange.min, gameOptions.sizeRange.max);
var height = Phaser.Math.Between(gameOptions.sizeRange.min, gameOptions.sizeRange.max);
// check if current box intersects other boxes
} while(this.boxesIntersect(startX, startY, width, height));
// draw the box
this.wallGraphics.strokeRect(startX, startY, width, height);
// insert box vertices into polygons array
this.polygons.push([[startX, startY], [startX + width, startY], [startX + width, startY + height], [startX, startY + height]]);
}
// method to check if the box intersects other boxes
boxesIntersect(x, y, w, h) {
// loop through existing boxes
for(let i = 0; i < this.polygons.length; i ++) {
// if the box intersects the existing i-th box...
if(x < this.polygons[i][1][0] && x + w > this.polygons[i][0][0] && y < this.polygons[i][3][1] && y + h > this.polygons[i][0][1]){
// return true
return true;
}
}
// if we reach the end of the loop, return false
return false;
}
// method to render the light
renderLight(pointer) {
// determine light polygon starting from pointer coordinates
let visibility = this.createLightPolygon(pointer.x, pointer.y);
// clear and prepare lightGraphics graphic object
this.lightGraphics.clear();
this.lightGraphics.lineStyle(2, 0xff8800);
this.lightGraphics.fillStyle(0xffff00);
// begin a drawing path
this.lightGraphics.beginPath();
// move the graphic pen to first vertex of light polygon
this.lightGraphics.moveTo(visibility[0][0], visibility[0][1]);
// loop through all light polygon vertices
for(let i = 1; i <= visibility.length; i ++) {
// draw a line to i-th light polygon vertex
this.lightGraphics.lineTo(visibility[i % visibility.length][0], visibility[ i %visibility.length][1]);
}
// close, stroke and fill light polygon
this.lightGraphics.closePath();
this.lightGraphics.fillPath();
this.lightGraphics.strokePath();
}
// method to create light polygon using visibility_polygon.js
createLightPolygon(x, y) {
let segments = VisibilityPolygon.convertToSegments(this.polygons);
segments = VisibilityPolygon.breakIntersections(segments);
let position = [x, y];
if (VisibilityPolygon.inPolygon(position, this.polygons[this.polygons.length - 1])) {
return VisibilityPolygon.compute(position, segments);
}
return null;
}
}
let config = {
type: Phaser.AUTO,
parent: "game",
width: "100%",
height: "100%",
physics: {
default: 'arcade',
arcade: {
gravity: {y: 200}
}
},
scene: {
scene: playGame
}
};
let game = new Phaser.Game(config);
});

103
client/main.sass Normal file
View File

@@ -0,0 +1,103 @@
/* CSS declarations go here */
body
padding: 10px
font-family: sans-serif
background-color: #315481
background-image: linear-gradient(to bottom, #315481, #918e82 100%)
background-attachment: fixed
position: absolute
top: 0
bottom: 0
left: 0
right: 0
padding: 0
margin: 0
font-size: 14px
.container
max-width: 600px
margin: 0 auto
min-height: 100%
background: white
header
background: #d2edf4
background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%)
padding: 20px 15px 15px 15px
position: relative
#login-buttons
display: block
h1
font-size: 1.5em
margin: 0
margin-bottom: 10px
display: inline-block
margin-right: 1em
form
margin-top: 10px
margin-bottom: -10px
position: relative
.new-task input
box-sizing: border-box
padding: 10px 0
background: transparent
border: none
width: 100%
padding-right: 80px
font-size: 1em
.new-task input:focus
outline: 0
ul
margin: 0
padding: 0
background: white
.delete
float: right
font-weight: bold
background: none
font-size: 1em
border: none
position: relative
li
position: relative
list-style: none
padding: 15px
border-bottom: #eee solid 1px
li .text
margin-left: 10px
li.checked
color: #888
li.checked .text
text-decoration: line-through
li.private
background: #eee
border-color: #ddd
header .hide-completed
float: right
.toggle-private
margin-left: 5px
@media (max-width: 600px)
li
padding: 12px 15px
.search
width: 150px
clear: both
.new-task input
padding-bottom: 5px

2
imports/api/index.js Normal file
View File

@@ -0,0 +1,2 @@
import "./tasks.js";
import "./users.js";

71
imports/api/tasks.js Normal file
View File

@@ -0,0 +1,71 @@
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';
export const Tasks = new Mongo.Collection('tasks');
if (Meteor.isServer) {
// This code only runs on the server
Meteor.publish('tasks', function tasksPublication() {
return Tasks.find({
$or: [
{ private: { $ne: true } },
{ owner: this.userId },
],
});
});
}
Meteor.methods({
'tasks.insert'(text) {
check(text, String);
// Make sure the user is logged in before inserting a task
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
Tasks.insert({
text,
createdAt: new Date(),
owner: this.userId,
username: Meteor.users.findOne(this.userId).username,
});
},
'tasks.remove'(taskId) {
check(taskId, String);
const task = Tasks.findOne(taskId);
if (task.private && task.owner !== this.userId) {
// If the task is private, make sure only the owner can delete it
throw new Meteor.Error('not-authorized');
}
Tasks.remove(taskId);
},
'tasks.setChecked'(taskId, setChecked) {
check(taskId, String);
check(setChecked, Boolean);
const task = Tasks.findOne(taskId);
if (task.private && task.owner !== this.userId) {
// If the task is private, make sure only the owner can check it off
throw new Meteor.Error('not-authorized');
}
Tasks.update(taskId, { $set: { checked: setChecked } });
},
'tasks.setPrivate'(taskId, setToPrivate) {
check(taskId, String);
check(setToPrivate, Boolean);
const task = Tasks.findOne(taskId);
// Make sure only the task owner can make a task private
if (task.owner !== this.userId) {
throw new Meteor.Error('not-authorized');
}
Tasks.update(taskId, { $set: { private: setToPrivate } });
},
});

View File

@@ -0,0 +1,41 @@
/* eslint-env mocha */
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { assert } from 'chai';
import { Tasks } from './tasks.js';
if (Meteor.isServer) {
describe('Tasks', () => {
describe('methods', () => {
const userId = Random.id();
let taskId;
beforeEach(() => {
Tasks.remove({});
taskId = Tasks.insert({
text: 'test task',
createdAt: new Date(),
owner: userId,
username: 'tmeasday',
});
});
it('can delete owned task', () => {
// Find the internal implementation of the task method so we can
// test it in isolation
const deleteTask = Meteor.server.method_handlers['tasks.remove'];
// Set up a fake method invocation that looks like what the method expects
const invocation = { userId };
// Run the method with `this` set to the fake invocation
deleteTask.apply(invocation, [taskId]);
// Verify that the method does what we expected
assert.equal(Tasks.find().count(), 0);
});
});
});
}

10
imports/api/users.js Normal file
View File

@@ -0,0 +1,10 @@
import { Meteor } from 'meteor/meteor';
if (Meteor.isServer) {
Meteor.methods({
'users.login'() {
console.log("Login Called.");
}
});
}

View File

@@ -0,0 +1,5 @@
import { Accounts } from 'meteor/accounts-base';
Accounts.ui.config({
passwordSignupFields: 'USERNAME_ONLY'
});

100
imports/ui/App.svelte Normal file
View File

@@ -0,0 +1,100 @@
<script>
import {Meteor} from "meteor/meteor";
import {onMount} from 'svelte';
import {useTracker} from 'meteor/rdb:svelte-meteor-data';
import {BlazeTemplate} from 'meteor/svelte:blaze-integration';
import Task from './Task.svelte';
import {Tasks} from '../api/tasks.js'
let newTask = "";
let hideCompleted = false;
let tasks;
let currentUser;
onMount(async () => {
Meteor.subscribe('tasks');
});
$: incompleteCount = useTracker(() => Tasks.find({checked: {$ne: true}}).count());
$: currentUser = useTracker(() => Meteor.user());
const taskStore = Tasks.find({}, {sort: {createdAt: -1}});
$: {
tasks = $taskStore;
if (hideCompleted) {
tasks = tasks.filter(task => !task.checked);
}
}
function handleSubmit(event) {
Meteor.call("tasks.insert", newTask);
// Clear form
newTask = "";
}
function performLogin() {
//console.log("In Perform Login");
//Meteor.call("users.login");
let config = ServiceConfiguration.configurations.findOne({service: 'google'});
console.log(config);
let scope = config.scope;
let loginStyle = "popup";
Meteor.loginWithGoogle({requestPermissions: scope, loginStyle, requestOfflineToken: true}, (err) => {
if(err) {
console.log(err);
}
else {
console.log("Logged in");
}
})
}
function performLogout() {
Meteor.logout();
}
</script>
<div class="container">
<header>
<h1>Todo List ({ $incompleteCount })</h1>
<label className="hide-completed">
<input
type="checkbox"
bind:checked={hideCompleted}
/>
Hide Completed Tasks
</label>
<BlazeTemplate template="loginButtons"/>
{#if !$currentUser}
<button type="button" on:click={performLogin}>Login</button>
{:else}
<button type="button" on:click={performLogout}>Logout</button>
{/if}
{#if $currentUser}
<form class="new-task" on:submit|preventDefault={handleSubmit}>
<input
type="text"
placeholder="Type to add new tasks"
bind:value={newTask}
/>
</form>
{/if}
</header>
<ul>
{#each tasks as task}
<Task
key={task._id}
task={task}
/>
{/each}
</ul>
<div id="game" style="height: 400px; width: 400px">
</div>
</div>

56
imports/ui/Task.svelte Normal file
View File

@@ -0,0 +1,56 @@
<script>
import { useTracker } from 'meteor/rdb:svelte-meteor-data';
import { Tasks } from "../api/tasks.js";
export let key;
export let task;
let showPrivateButton;
$: currentUser = useTracker(() => Meteor.user());
$: {
showPrivateButton = false;
if($currentUser){
showPrivateButton = task.owner === $currentUser._id;
}
}
function toggleChecked() {
// Set the checked property to the opposite of its current value
Meteor.call("tasks.setChecked", task._id, !task.checked);
}
function deleteThisTask() {
Meteor.call("tasks.remove", task._id);
}
function togglePrivate() {
Meteor.call("tasks.setPrivate", task._id, !task.private);
}
</script>
<li class:checked="{task.checked}"
class:private="{task.private}" >
<button class="delete" on:click={deleteThisTask}>
&times;
</button>
<input
type="checkbox"
readonly
checked={!!task.checked}
on:click={toggleChecked}
/>
{#if showPrivateButton}
<button className="toggle-private" on:click="{togglePrivate}">
{ task.private ? "Private" : "Public" }
</button>
{/if}
<span class="text">
<strong>{ task.username }</strong>
: { task.text }
</span>
</li>

1542
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

28
package.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "simple-todos-svelte",
"private": true,
"scripts": {
"start": "meteor run",
"test": "meteor test --once --driver-package meteortesting:mocha",
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
"visualize": "meteor --production --extra-packages bundle-visualizer"
},
"dependencies": {
"@babel/runtime": "^7.8.3",
"connect-route": "^0.1.5",
"jquery": "^3.4.1",
"meteor-node-stubs": "^1.0.0",
"phaser": "3.55.2",
"svelte": "^3.27.0"
},
"meteor": {
"mainModule": {
"client": "client/main.js",
"server": "server/main.js"
},
"testModule": "tests/main.js"
},
"devDependencies": {
"chai": "^4.2.0"
}
}

27
server/google-oauth.js Normal file
View File

@@ -0,0 +1,27 @@
/**
* Google cloud platform: https://console.developers.google.com/apis/dashboard
* Setup a OAuth consent screen, then setup OAuth credentials.
* Loads the information from the /private/settings.json file.
*/
try {
let settingsFile = process.env.SETTINGS;
let settings = JSON.parse(Assets.getText(settingsFile));
if (settings) {
ServiceConfiguration.configurations.upsert({
service: "google"
}, {
$set: {
loginStyle: settings.google.loginStyle,
clientId: settings.google.clientId,
secret: settings.google.secret
}
}
);
} else {
console.log("Error: No settings file.");
}
} catch (err) {
console.log(err);
}

12
server/main.js Normal file
View File

@@ -0,0 +1,12 @@
import '../imports/api/';
import './google-oauth.js';
import connectRoute from 'connect-route';
// Got the below code from:
// https://docs.meteor.com/packages/webapp.html
WebApp.connectHandlers.use(connectRoute((router) => {
router.get('/ping', (req, res, next) => {
//TODO: Change ping / pong to something appropriate for a browser plugin reporting user/machine data and requesting updates.
res.end("pong");
});
}));

21
tests/main.js Normal file
View File

@@ -0,0 +1,21 @@
import assert from "assert";
import "../imports/api/tasks.tests.js";
describe("simple-todos-svelte", function () {
it("package.json has correct name", async function () {
const { name } = await import("../package.json");
assert.strictEqual(name, "simple-todos-svelte");
});
if (Meteor.isClient) {
it("client is not server", function () {
assert.strictEqual(Meteor.isServer, false);
});
}
if (Meteor.isServer) {
it("server is not client", function () {
assert.strictEqual(Meteor.isClient, false);
});
}
});