Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 72 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,73 @@
./scripts/bootstrap.sh
# Todo List App

The Todo List App is an application for creating and sharing todolists.

This repo contains:

* Resources for creating users, todo lists, todos, and todo list permissions.
* User tests for the above resources.


## Environment Setup

Clone the repository:

`git clone https://github.com/cfierro/todo.git`

Grab your fork:

'git remote add [yourname] https://github.com/[yourname]/todo.git'

Install dependencies using the bootstrap script:

`./scripts/bootstrap.sh`


## Directory Structure
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps also add documentation about the js side of our app below now too.


* app/authentication - resources for user authentication
* log in
* log out
* get logged in user info
* app/lib - shared libraries across multiple resources
* /authenticaion - decorator for requiring a user to be logged in
* /models - includes a base table mixin for all data tables
* /response_uit - methods for building status responses
* /status - classes for returning raised exceptions
* app/permissions - model and resources for list permissions
* app/todo_lists - model and resources for todo lists
* app/todos - model and resources for todos
* app/users - model and resources for users
* app/__init__.py - initialize python packages. Includes:
* Import Flask libraries
* Error handler
* database creation
* Model imports
* Resources urls for APIs
* env - virtual environment
* scripts - bootstrap script fo installing dependencies
* unittest/resources - unittests for user, todo, todo_list, and auth resources
* .gitignore - files to ignore upon git commit
* config.py -
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a reminder, the config.py file in flask is used to set application settings as well as set some variables that you could use in your code, for example, feature flag settings..

* README.md - this file!
* requirements.txt - required libraries
* run.py - runs the application.
* shell.py -
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove the shell.py file and delete this line? That file really hasn't been useful.



## Development

Run the following from the top level directory:

Activate your virutual environment.

`source env/bin/activate`

To run the app:

`python run.py`
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can update this to use our npm run start command now.


To run unit tests:

`py.test unittest`

source env/bin/activate
Binary file modified app.db
Binary file not shown.
34 changes: 34 additions & 0 deletions app/static/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
body {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is just output from our compiled sass file, it would be great if we didn't track it in our git history. Could you this file to our .gitignore?

font-family: 'Josefin Sans', sans-serif;
font-size: 18px;
background: #BAA5D6; }

.todo-app h1 {
text-align: center; }

.todo-lists-container {
width: 50%;
margin: 0 auto; }
.todo-lists-container ul {
list-style: none;
margin-left: 0;
padding-left: 0; }

.listName {
outline: none;
border: none;
background: transparent;
font-family: 'Josefin Sans', sans-serif;
font-size: 1.5em;
text-align: center;
width: 80%; }
.listName:focus + .deleteList {
display: inline-block; }

.todo {
outline: none;
padding: 3px;
width: 80%; }

.addList {
margin: 0 auto; }
1 change: 1 addition & 0 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html>
<head>
<title></title>
<link href='https://fonts.googleapis.com/css?family=Josefin+Sans:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="static/css/main.css">
</head>
<body>
Expand Down
11 changes: 8 additions & 3 deletions app/todo_lists/resources.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

from flask import request, session
from flask_restful import Resource
from sqlalchemy import and_
Expand Down Expand Up @@ -30,10 +32,12 @@ def get(self):
def post(self):
"""Method creates a todoList and returns it in an Ok response.
"""
if not(request.form.get('name')):
data = json.loads(request.data)

if not(data.get('name')):
raise status.BadRequest()

todoList = TodoList(request.form.get('name'), session.get('userId'))
todoList = TodoList(data.get('name'), session.get('userId'))
db.session.add(todoList)
db.session.commit()

Expand All @@ -56,6 +60,7 @@ def put(self, todoListId):
"""
userId = session.get('userId')
todoList = TodoList.query.get(todoListId)
data = json.loads(request.data)

if todoList is None:
raise status.NotFound()
Expand All @@ -67,7 +72,7 @@ def put(self, todoListId):
if permission is None:
raise status.Unauthorized()

todoList.name = request.form.get('name') or todoList.name
todoList.name = data.get('name') or todoList.name
db.session.commit()

return response_util.buildOkResponse(todoList.toDict())
Expand Down
35 changes: 21 additions & 14 deletions app/todos/resources.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

from flask import request, session
from flask_restful import Resource
from sqlalchemy import and_
Expand Down Expand Up @@ -44,10 +46,11 @@ def get(self):
def post(self):
"""Method adds a new todo and returns the todo in an OK response..
"""
data = json.loads(request.data)
userId = session.get('userId')
todoListId = request.form.get('todoListId')
todoListId = data.get('todoListId')

if not(request.form.get('subject') and todoListId):
if not(data.get('subject') and todoListId):
raise status.BadRequest()

permission = TodoListPermission.query.filter(
Expand All @@ -57,14 +60,14 @@ def post(self):
if permission is None:
raise status.Forbidden()

todo = Todo(request.form.get('subject'),
todo = Todo(data.get('subject'),
todoListId,
userId,
request.form.get('dueDate'),
request.form.get('description'),
request.form.get('priority'),
request.form.get('completed'),
request.form.get('assigneeId'))
data.get('dueDate'),
data.get('description'),
data.get('priority'),
data.get('completed'),
data.get('assigneeId'))
db.session.add(todo)
db.session.commit()

Expand All @@ -81,6 +84,7 @@ def put(self, todoId):
Args:
todoId - Interger, primary key identifying the todo.
"""
data = json.loads(request.data)
userId = session.get('userId')
todo = Todo.query.get(todoId)

Expand All @@ -94,12 +98,15 @@ def put(self, todoId):
if permission is None:
raise status.Forbidden()

todo.subject = request.form.get('subject') or todo.subject
todo.dueDate = request.form.get('dueDate') or todo.dueDate
todo.description = request.form.get('description') or todo.description
todo.priority = request.form.get('priority') or todo.priority
todo.completed = request.form.get('completed') or todo.completed
todo.assigneeId = request.form.get('assigneeId') or todo.assigneeId
todo.subject = data.get('subject') or todo.subject
todo.dueDate = data.get('dueDate') or todo.dueDate
todo.description = data.get('description') or todo.description
todo.priority = data.get('priority') or todo.priority
todo.assigneeId = data.get('assigneeId') or todo.assigneeId

todo.completed = data.get('completed') \
if data.get('completed') != todo.completed \
else todo.completed

db.session.commit()

Expand Down
13 changes: 13 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('styles', function() {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a small comment on this task too? As you did below.

gulp.src('sass/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./app/static/css'));
});

//Watch task
gulp.task('default',function() {
gulp.watch('sass/**/*.scss',['styles']);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job! Just a couple of very minor nits. Could you add a space between // and the W. // Watch task. Could also add a space between parameters so that it is ('default', function() { and ('sass/**/*.scss', ['styles'])

});
Empty file added index.js
Empty file.
9 changes: 0 additions & 9 deletions js/src/Collection/ItemCollection.js

This file was deleted.

18 changes: 18 additions & 0 deletions js/src/Collection/TodoCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var Backbone = require('backbone');

var TodoModel = require('../Model/TodoModel.js');

var TodoCollection = Backbone.Collection.extend({
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a comment to the whole class is also a good idea. Could be a simple comment, such as,

/**
 * TodoCollection is a collection of todos that belong to a given todo list.
 */

initialize: function(models, options){
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment to this constructor? Comment format for a function is usually:

/**
 * Comment about overall function.
 *
 * @param {data type} param1 Comment about param1
 * 
 * @return {data type} Comment about return (optional)
 */

So for example:

/**
 * Constructor. Initializes a new collection for todos that have the specified todo list ID.
 * 
 * @param {Array.<TodoModel>} models Array of models.
 * @param {Object} options The options with keys:
 *     @param {string} options.id ID for this todo list (todo collection).
 */

this.id = options.id
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a semi-colon

},
model: TodoModel,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I typically see this moved all the way to the top, so that the reader knows immediately what models this collection should hold. Also, could you add a comment. For properties and variables in the defaults dictionary, the comment is very similar:

/**
 * Comment if necessary.
 * @type {data type}
 */

So for example:

/**
 * The collection's model.
 * @type {TodoModel}
 */

url: function(){
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment for this function.

return '/todos?todoListId=' + this.id;
},
parse: function(response){
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment for this function.

return response.result;
}
})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs a semi-colon.


module.exports = TodoCollection;
13 changes: 13 additions & 0 deletions js/src/Collection/TodoListCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var Backbone = require('backbone');

var TodoListModel = require('../Model/TodoListModel.js');

var TodoListCollection = Backbone.Collection.extend({
model: TodoListModel,
url: '/todolists',
parse: function(response){
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add comments to the properties and functions in this collection?

return response.result;
}
})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs semi-colon. Things like if statements, functions, for loops don't need a semi-colon, but expressions, such as var x = 1;, return response.result;, do need one.


module.exports = TodoListCollection;
10 changes: 0 additions & 10 deletions js/src/Model/ItemModel.js

This file was deleted.

18 changes: 18 additions & 0 deletions js/src/Model/TodoListModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var Backbone = require('backbone');
// var TodoListCollection = require('../Collection/TodoListCollection.js')
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's delete unused imports or commented out code like this :)


var TodoListModel = Backbone.Model.extend({
urlRoot: '/todolists',
defaults: {
name: 'List Name',
creator: 'User'
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a reminder, you use the same kind of comment for class properties as you would for these default attributes.

/**
 * Comment if necessary.
 * @type {data type}
 */

},
parse: function(response, options){
if (options.collection) {
return response;
}
return response.result;
}
})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add semi-colons and comments where necessary in this file?


module.exports = TodoListModel;
21 changes: 21 additions & 0 deletions js/src/Model/TodoModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var Backbone = require('backbone');

var TodoModel = Backbone.Model.extend({
urlRoot: 'todos/',
defaults: {
subject: 'Subject',
dueDate: null,
description: '',
priority: null,
completed: false,
assignee: null,
},
parse: function(response, options){
if (options.collection) {
return response;
}
return response.result;
}
})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, please add semi-colons and comments where necessary.


module.exports = TodoModel;
11 changes: 11 additions & 0 deletions js/src/Model/UserModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var Backbone = require('backbone');

var UserModel = Backbone.Model.extend({
url: '/me',
parse: function(response){
return response.result;
}

})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove unnecessary white space (empty line 8), and add a few comments.


module.exports = UserModel;
Loading