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
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>