Skip to content

Commit

Permalink
Merge b12bcf9 into 5d1dc47
Browse files Browse the repository at this point in the history
  • Loading branch information
Nwuguru Sunday committed May 24, 2016
2 parents 5d1dc47 + b12bcf9 commit 3a1fc38
Show file tree
Hide file tree
Showing 30 changed files with 1,467 additions and 1 deletion.
1 change: 1 addition & 0 deletions .coverage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!coverage.py: This is a private format, don't read it directly!{"lines": {"/Users/andela/Documents/projects/flaskapps/bucketlist-api/app/views.py": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 18, 21, 23], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/test.py": [1, 3, 4], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/app/resource.py": [1, 2, 3, 4, 5, 7, 9, 16, 17, 18, 20, 22, 28, 30, 31, 42, 43, 44, 45, 47, 49, 60, 61, 62, 63, 65, 66, 68, 71, 73, 86, 87, 88, 89, 90, 92, 94, 97, 100, 102, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 129, 132, 134, 147, 148, 149, 150, 153, 154, 155, 157, 160, 162, 173, 174, 175, 178, 179, 182, 184, 195, 196, 197, 198, 200, 201, 204, 207, 209, 223, 224, 225, 226, 227, 229, 230, 233, 234, 235, 237, 240, 243, 245, 259, 260, 261, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 280, 283, 285, 298, 299, 300, 301, 302, 304, 305, 308, 312, 313, 324, 325, 327, 328, 330, 333, 335, 348, 349, 350, 351, 353], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/app/helper.py": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 22, 23, 24, 27, 31, 32, 33, 34, 35, 37, 42, 43, 44, 45, 47, 49, 53, 55, 60, 61, 62, 63, 64, 66, 71, 72, 73, 74, 75], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/test_config.py": [1, 2, 4, 6], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/app/models.py": [1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 71, 72, 74, 75, 76, 77, 78, 79, 80, 83, 84, 85], "/Users/andela/Documents/projects/flaskapps/bucketlist-api/production_config.py": [1, 2, 4, 6]}}
6 changes: 6 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[report]
omit =
*/python?.?/*
tests/*
*/site-packages/nose/*
*__init__*
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pyc
*/*.pyc
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: python
python:
- "2.7"
# command to install dependencies
install:
- pip install -r requirements.txt
script:
- nosetests --with-coverage
after_success:
- coveralls
146 changes: 145 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,146 @@
# bucketlist-api
# bucketlist API
[![Build Status](https://travis-ci.org/andela-snwuguru/bucketlist-api.svg?branch=ch-ci-integration)](https://travis-ci.org/andela-snwuguru/bucketlist-api) [![Coverage Status](https://coveralls.io/repos/github/andela-snwuguru/bucketlist-api/badge.svg?branch=ch-ci-integration)](https://coveralls.io/github/andela-snwuguru/bucketlist-api?branch=ch-ci-integration)

According to Merriam-Webster Dictionary, a Bucket List is a list of things that one has not done before but wants to do before dying.
This is a checkpoint 2 project used to evaluate Python beginner

## Features, Endpoints and Accessiblity
<table>
<tr>
<th> Features </th>
<th> Endpoint</th>
<th> Public</th>
</tr>
<tr>
<td>Register </td>
<td>POST /auth/register</td>
<td> True</td>
</tr>
<tr>
<td>Authentication</td>
<td>POST /auth/login</td>
<td>True</td>
</tr>

<tr>
<td>Create Bucketlist</td>
<td>POST /bucketlists/ </td>
<td>False</td>
</tr>

<tr>
<td>Fetch Bucketlists</td>
<td>GET /bucketlists/ </td>
<td>False</td>
</tr>

<tr>
<td>Fetch Single Bucketlists</td>
<td>GET /bucketlists/:id </td>
<td>False</td>
</tr>

<tr>
<td>Update bucketlist record</td>
<td>PUT /bucketlists/:id </td>
<td>False</td>
</tr>

<tr>
<td>Delete bucketlist record</td>
<td>DELETE /bucketlists/:id </td>
<td>False</td>
</tr>

<tr>
<td>Create Bucketlist Item</td>
<td>POST /bucketlists/:id/items </td>
<td>False</td>
</tr>

<tr>
<td>Fetch Bucketlists Items</td>
<td>GET /bucketlists/:id/items </td>
<td>False</td>
</tr>

<tr>
<td>Fetch Single Bucketlists item</td>
<td>GET /bucketlists/:id/items/:itemId </td>
<td>False</td>
</tr>

<tr>
<td>Update bucketlist item record</td>
<td>PUT /bucketlists/:id/items/:itemId </td>
<td>False</td>
</tr>

<tr>
<td>Delete bucketlist item record</td>
<td>DELETE /bucketlists/:id/items/:itemId </td>
<td>False</td>
</tr>

</table>

## Dependecies
All dependecies can be found in requirements.txt

## How to use
- Clone project git clone `` git@github.com:andela-snwuguru/bucketlist-api.git ``
- Create a virtual environment `` mkvirtualenv bucketlist ``
- Install dependecies `` pip install -r requirements.txt ``
- Navigate to project folder `` cd ~/bucketlist-api ``
- Run migrationscript
```
python script.py db migrate
python script.py db upgrade
```
- Run Project `` python run.py ``

## Sample Request

#### Register new User
```
Request
--------
http POST http://127.0.0.1:5000/api/v1.0/auth/register username=guru password=test email=guru@mail.com
Response
--------
{
"data": {
"date_created": "2016-05-19 19:37:20",
"date_modified": "2016-05-19 19:37:20",
"email": "guru@mail.com",
"id": 7,
"username": "guru"
}
}
```

#### Retrieve Access Token
```
Request
--------
http POST http://127.0.0.1:5000/api/v1.0/auth/login username=guru password=test
Response
--------
{
"data": {
"date_created": "2016-05-19 19:37:20",
"date_modified": "2016-05-19 19:37:20",
"email": "guru@mail.com",
"id": 7,
"username": "guru"
},
"token": "098f6bcd4621d373cade4e832627b4f6|7|.Ch-n_A._bH9Hx_kpibiIlRHvFRZbVt-6UM"
}
```

### Documentation

Api documentation is still in progress, it Will soon be available.
Binary file added app.db
Binary file not shown.
11 changes: 11 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import request

app = Flask(__name__)

#server = request.args.get('server','production').lower()
app.config.from_object('production_config')
db = SQLAlchemy(app)

from app import views
75 changes: 75 additions & 0 deletions app/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from flask_restful import reqparse
import hashlib
from itsdangerous import TimestampSigner
from app import db

encrypt_key = 'bucketlists api'

def save(model):
""" Save a row in the database """
try:
db.session.add(model)
db.session.commit()
return True
except:
return False

def delete(model):
""" Deletes a row from the database """
try:
db.session.delete(model)
db.session.commit()
return True
except:
return False


def get_user_id_from_token(token):
"""
This method extracts the user id from provided access token
"""
data = token.split('|')
try:
return data[1]
except:
return 0

def validate_args(fields={}):
"""
This method helps to parse and validate provided parameters.
It will return parsed argument if the require fields are in request
"""
parser = reqparse.RequestParser()
for field in fields.keys():
help_message = field + ' can not be blank'
parser.add_argument(field, required=fields[field], help=help_message)

return parser.parse_args()

def md5(string):
"""
This method will return md5 hash of a given string
"""
return hashlib.md5(string.encode("utf")).hexdigest()

def encrypt(string):
"""
This method will return encrypted version of a string.
It will return False if encryption fails
"""
try:
signer = TimestampSigner(encrypt_key)
return signer.sign(string)
except:
return False

def decrypt(string, max_age=15000):
"""
This method will return decrypted version of an encrypted string.
If age of encryption is greater than max age it will return False
"""
try:
signer = TimestampSigner(encrypt_key)
return signer.unsign(string, max_age=max_age)
except:
return False
85 changes: 85 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from app import db
from datetime import datetime
from app.helper import encrypt, decrypt


class BucketListModel(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(255), unique=True)
created_by = db.Column(db.Integer, db.ForeignKey('user.id'))
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
user = db.relationship('User', backref=db.backref('bucketlists', lazy='dynamic'))

def __init__(self, name, user):
self.name = name
self.user = user

def get(self):
return {
'id':self.id,
'name':self.name,
'created_by':self.user.username,
'date_created':str(self.date_created),
'date_modified':str(self.date_modified)
}

def __repr__(self):
return '<BucketListModel %r>' % self.name


class BucketListItemModel(db.Model):
id = db.Column(db.Integer(), primary_key=True)
task = db.Column(db.String(255))
done = db.Column(db.Boolean(), default=False)
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
bucketlist_id = db.Column(db.Integer, db.ForeignKey('bucket_list_model.id'))
bucketlist = db.relationship('BucketListModel', backref=db.backref('items', lazy='dynamic'))

def __init__(self, task, bucketlist):
self.task = task
self.bucketlist = bucketlist

def get(self):
return {
'id':self.id,
'task':self.task,
'done':self.done,
'bucketlists':self.bucketlist.name,
'date_created':str(self.date_created),
'date_modified':str(self.date_modified)
}

def __repr__(self):
return '<BucketListItemModel %r>' % self.task


class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100), unique=True)
password = db.Column(db.String(20))
email = db.Column(db.String(200), unique=True)
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())

def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = password

def __repr__(self):
return '<User %r>' % self.username

def get(self):
return {
'id':self.id,
'username':self.username,
'email':self.email,
'date_created':str(self.date_created),
'date_modified':str(self.date_modified),
}

def generate_token(self):
string = str(self.password) + '|' + str(self.id) + '|'
return encrypt(string)

0 comments on commit 3a1fc38

Please sign in to comment.