";
+
+ document.getElementById("user-account").innerHTML = output;
+ document.getElementById("response_status").innerHTML = "Get User account succeeded";
+ }
+ else {
+ document.getElementById("response_status").innerHTML = "Get User account failed";
+ }
+});
+
+function logout() {
+ ajax_post(API_ENDPOINT + '/users/expire', {'token': localStorage.getItem("token")}, function(data) {
+ if (data.status) {
+ localStorage.setItem("token", '');
+ document.getElementById("response_status").innerHTML = "User logout succeeded";
+ }
+ else {
+ document.getElementById("response_status").innerHTML = "User logout failed";
+ }
+});
+}
+
+
+
diff --git a/src/html/users/register.html b/src/html/users/register.html
new file mode 100644
index 0000000..c3a36a2
--- /dev/null
+++ b/src/html/users/register.html
@@ -0,0 +1,41 @@
+
+
+
+
Register
+
+
+
+
+
Register
+
+
+
+
+
+
+
+
diff --git a/src/html/users/register.js b/src/html/users/register.js
new file mode 100644
index 0000000..db6dbf7
--- /dev/null
+++ b/src/html/users/register.js
@@ -0,0 +1,48 @@
+var API_ENDPOINT = "http://localhost:8080"
+
+function ajax_post(url, data, callback) {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.onreadystatechange = function() {
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 201) {
+ console.log('responseText:' + xmlhttp.responseText);
+ try {
+ var data = JSON.parse(xmlhttp.responseText);
+ } catch(err) {
+ document.getElementById("demo_dbg").innerHTML = err.message + " in " + xmlhttp.responseText;
+ console.log(err.message + " in " + xmlhttp.responseText);
+ return ;
+ }
+ callback(data);
+ }else{
+
+ document.getElementById("demo_dbg").innerHTML = xmlhttp.responseText;
+ }
+ };
+
+ xmlhttp.open("POST", url, true);
+ xmlhttp.setRequestHeader("Content-type", "application/json");
+ xmlhttp.send(JSON.stringify(data));
+}
+
+function registerSubmit() {
+ var fullname = document.forms["registerForm"]["fullname"].value;
+ var age = document.forms["registerForm"]["age"].value;
+ var username = document.forms["registerForm"]["username"].value;
+ var password = document.forms["registerForm"]["password"].value;
+ var data = {
+ 'fullname': fullname,
+ 'age': age,
+ 'username': username,
+ 'password': password
+ }
+
+ ajax_post(API_ENDPOINT + '/users/register', data, function(data) {
+ if (data.status) {
+ document.getElementById("response_status").innerHTML = "
Register User succeeded
";
+ } else {
+ document.getElementById("response_status").innerHTML = "
Register User failed
";
+ }
+ });
+ return false;
+}
+
diff --git a/src/service/__init__.py b/src/service/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/service/__init__.py
@@ -0,0 +1 @@
+
diff --git a/src/service/app.py b/src/service/app.py
index ade6772..72176dd 100644
--- a/src/service/app.py
+++ b/src/service/app.py
@@ -1,55 +1,44 @@
#!/usr/bin/python
-
+# todo:reorder and rearrange
from flask import Flask
from flask_cors import CORS
-import json
+from flask_mongoengine import MongoEngine
import os
+import sys
+
+sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '../../')))
+
+
+db = MongoEngine()
-app = Flask(__name__)
-# Enable cross origin sharing for all endpoints
-CORS(app)
-
-# Remember to update this list
-ENDPOINT_LIST = ['/', '/meta/heartbeat', '/meta/members']
-
-def make_json_response(data, status=True, code=200):
- """Utility function to create the JSON responses."""
-
- to_serialize = {}
- if status:
- to_serialize['status'] = True
- if data is not None:
- to_serialize['result'] = data
- else:
- to_serialize['status'] = False
- to_serialize['error'] = data
- response = app.response_class(
- response=json.dumps(to_serialize),
- status=code,
- mimetype='application/json'
- )
- return response
+def create_app(**config_overrides):
+ app = Flask(__name__, static_folder='static', static_url_path='')
-@app.route("/")
-def index():
- """Returns a list of implemented endpoints."""
- return make_json_response(ENDPOINT_LIST)
+ # Load config.
+ from views import views
+ app.register_blueprint(views)
+ # apply overrides
+ app.config.update(config_overrides)
-@app.route("/meta/heartbeat")
-def meta_heartbeat():
- """Returns true"""
- return make_json_response(None)
+ # Setup the database.
+ db.init_app(app)
+ return app
-@app.route("/meta/members")
-def meta_members():
- """Returns a list of team members"""
- with open("./team_members.txt") as f:
- team_members = f.read().strip().split("\n")
- return make_json_response(team_members)
+# app = create_app(
+ # MONGODB_SETTINGS={'db': 'db_deploy', 'host': 'mongodb'},
+ # TESTING=True,
+ # SALT='IfHYBwi5ZUFZD9VaonnK',
+# )
+# app = None
+# SALT = 'dfdf'
+# SALT = app.config.get('SALT')
+
+
+# Enable cross origin sharing for all endpoints
if __name__ == '__main__':
# Change the working directory to the script directory
@@ -57,5 +46,12 @@ def meta_members():
dname = os.path.dirname(abspath)
os.chdir(dname)
+ app = create_app(
+ MONGODB_SETTINGS={'db': 'db_deploy', 'host': 'mongodb'},
+ TESTING=True,
+ SALT='IfHYBwi5ZUFZD9VaonnK',
+ )
+ CORS(app)
+
# Run the application
app.run(debug=False, port=8080, host="0.0.0.0")
diff --git a/src/service/db_example.py b/src/service/db_example.py
new file mode 100644
index 0000000..a4b75f3
--- /dev/null
+++ b/src/service/db_example.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+import datetime
+import flask
+import bson
+import uuid
+import json
+
+sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '../../')))
+
+from flask_mongoengine import MongoEngine
+
+app = flask.Flask(__name__)
+app.config.from_object(__name__)
+app.config['MONGODB_SETTINGS'] = {'DB': 'db_test'}
+app.config['TESTING'] = True
+app.config['SECRET_KEY'] = 'flask+mongoengine=<3'
+app.debug = True
+db = MongoEngine()
+db.init_app(app)
+
+
+class User(db.Document):
+ uid = db.SequenceField()
+ name = db.StringField()
+ password = db.StringField()
+ registered_date = db.DateTimeField(default=datetime.datetime.now)
+
+ def __repr__(self):
+ return 'id=%s, data = [%s:%s]'%(self.pk,self.name,self.password)
+
+class Token(db.Document):
+ token = db.StringField()
+ expiry = db.DateTimeField(default=datetime.datetime.now()+datetime.timedelta(days=1))
+ isexpired = db.BooleanField()
+ data = db.StringField()
+ def __repr__(self):
+ return 'token=%s, data = [%s]'%(self.token,self.data)
+
+class Counter(db.Document):
+ count = db.IntField()
+ def __repr__(self):
+ return 'counter = %d'%(self.count)
+
+
+
+# insert
+def test_insert():
+ count = Counter(count=0)
+ count.save()
+ dtnow = datetime.datetime.now()
+ print dtnow.isoformat()
+
+ user = User(name='TestUser',password='asdf')
+ user.save()
+
+ user = User(name='TestUser2',password='asdf')
+ user.save()
+
+ user = User(name='TestUser3',password='asdf')
+ user.save()
+
+ data = {'pk':str(user.pk),'ip':'127.0.0.1'}
+ token = Token(token=str(uuid.uuid4()),data = json.dumps(data))
+ token.save()
+
+ data2 = {'pk':str(user.pk),'ip':'127.0.0.1'}
+ token = Token(token=str(uuid.uuid4()),data = json.dumps(data2))
+ token.save()
+
+ data3 = {'pk':str(user.pk),'ip':'127.0.0.1'}
+ token = Token(token=str(uuid.uuid4()),data = json.dumps(data3))
+ token.save()
+
+ count = Counter.objects()[0]
+ count1 = count.count + 1
+ count.update(count=count1)
+
+
+
+def test_update():
+ objs = User.objects(name='TestUser2')
+ objs[0].update(name='testchanged')
+
+ obj = User.objects(name='TestUser3').first()
+ obj.update(name='testchanged3')
+
+def test_delete():
+ objs=User.objects(name='TestUser')
+ objs[0].delete()
+
+def test_searchby_pk():
+ pk = User.objects()[0].pk
+ print User.objects(pk=pk)
+User.drop_collection()#clear all User collection
+test_insert()
+print User.objects()
+results = Token.objects()
+for result in results:
+ print result.token
+print Counter.objects()
+#test_update()
+#print User.objects()
+#test_delete()
+#print User.objects()
+#test_searchby_pk()
+
diff --git a/src/service/flask_app.py b/src/service/flask_app.py
new file mode 100644
index 0000000..7fe0b1d
--- /dev/null
+++ b/src/service/flask_app.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+# todo:reorder and rearrange
+from flask import Flask
+from flask_cors import CORS
+from flask_mongoengine import MongoEngine
+import os
+import sys
+
+sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '../../')))
+
+
+db = MongoEngine()
+
+
+def create_app(**config_overrides):
+ app = Flask(__name__, static_folder='static', static_url_path='')
+
+ # Load config.
+ from views import views
+ app.register_blueprint(views)
+
+ # apply overrides
+ app.config.update(config_overrides)
+
+ # Setup the database.
+ db.init_app(app)
+
+ return app
+
+
+app = create_app(
+ MONGODB_SETTINGS={'db': 'db_deploy', 'host': 'mongodb'},
+ TESTING=True,
+ SALT='IfHYBwi5ZUFZD9VaonnK',
+)
+# app = None
+# SALT = 'dfdf'
+SALT = app.config.get('SALT')
+
+
+# Enable cross origin sharing for all endpoints
+
+# if __name__ == '__main__':
+ # # Change the working directory to the script directory
+ # abspath = os.path.abspath(__file__)
+ # dname = os.path.dirname(abspath)
+ # os.chdir(dname)
+
+ # app = create_app(
+ # MONGODB_SETTINGS={'db': 'db_deploy', 'host': 'mongodb'},
+ # TESTING=True,
+ # SALT='IfHYBwi5ZUFZD9VaonnK',
+ # )
+ # CORS(app)
+
+ # # Run the application
+ # app.run(debug=False, port=8080, host="0.0.0.0")
diff --git a/src/service/models.py b/src/service/models.py
new file mode 100644
index 0000000..6027f64
--- /dev/null
+++ b/src/service/models.py
@@ -0,0 +1,77 @@
+from flask import current_app, request
+from app import db
+import datetime
+import json
+
+
+def is_token_valid(token_str):
+ token = Token.objects(token=token_str).first()
+ if token is None: return False
+ if token.isexpired: return False
+ if token.expiry < datetime.datetime.now(): return False
+
+ token_data = json.loads(token.data)
+ if request.remote_addr != token_data['ip']: return False
+ return True
+
+
+def db_object_to_json(doc):
+ ret = {}
+ print doc._fields
+ # field_dict = doc.get_fields_info()
+ for field in doc._fields:
+ current_app.logger.info(field)
+ ret[field] = str(doc[field])
+ return json.dumps(ret)
+
+
+def db_object_to_dict(doc):
+ ret = {}
+ # field_dict = doc.get_fields_info()
+ for field in doc._fields:
+ current_app.logger.info(field)
+ ret[field] = str(doc[field])
+ return ret
+
+
+class User(db.Document):
+ username = db.StringField()
+ hashed_password = db.StringField()
+ password = db.StringField()
+ fullname = db.StringField()
+ age = db.IntField()
+ registered_date = db.DateTimeField(default=datetime.datetime.now)
+
+ def __str__(self):
+ return self.__repr__();
+
+ def __repr__(self):
+ return db_object_to_json(self)
+
+
+class Token(db.Document):
+ token = db.StringField()
+ expiry = db.DateTimeField(default=datetime.datetime.now() + datetime.timedelta(days=1))
+ isexpired = db.BooleanField()
+ data = db.StringField()
+
+ def __str__(self):
+ return self.__repr__();
+
+ def __repr__(self):
+ return db_object_to_json(self)
+
+
+class Diary(db.Document):
+ id = db.SequenceField(primary_key=True)
+ title = db.StringField()
+ username = db.StringField()
+ published_time = db.StringField() # ISO8601
+ public = db.BooleanField()
+ text = db.StringField()
+
+ def __str__(self):
+ return self.__repr__();
+
+ def __repr__(self):
+ return db_object_to_json(self)
diff --git a/src/service/start_services.sh b/src/service/start_services.sh
index a970fe8..83431ed 100644
--- a/src/service/start_services.sh
+++ b/src/service/start_services.sh
@@ -1,4 +1,4 @@
#!/bin/bash
apachectl start
-python /service/app.py
+python app.py
diff --git a/src/service/team_members.txt b/src/service/team_members.txt
index 50bdea8..60c5c6b 100644
--- a/src/service/team_members.txt
+++ b/src/service/team_members.txt
@@ -1,3 +1,4 @@
-Jeremy Heng
-John Galt
-Audrey Shida
+Zawlin
+Xue Si
+Shi Qing
+Chen Hui
diff --git a/src/service/views.py b/src/service/views.py
new file mode 100644
index 0000000..5845d4b
--- /dev/null
+++ b/src/service/views.py
@@ -0,0 +1,407 @@
+from flask import current_app, Blueprint, request
+from models import is_token_valid, User, Token, Diary, db_object_to_dict, db_object_to_json
+import datetime
+import hashlib
+import json
+import uuid
+from bson import ObjectId
+
+views = Blueprint('views', __name__)
+
+# Remember to update this list
+ENDPOINT_LIST = ['/', '/meta/heartbeat', '/meta/members',
+ '/users', '/users/register', '/users/authenticate', '/users/expire',
+ '/diary', '/diary/create', '/diary/delete', '/diary/permission']
+
+
+def make_json_response(data, status=True, code=200):
+ """Utility function to create the JSON responses."""
+
+ to_serialize = {}
+ if status:
+ to_serialize['status'] = True
+ if data is not None:
+ to_serialize['result'] = data
+ else:
+ to_serialize['status'] = False
+ to_serialize['error'] = data
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route('/')
+def index():
+ """Returns a list of implemented endpoints."""
+ return make_json_response(ENDPOINT_LIST)
+
+
+@views.route("/meta/heartbeat")
+def meta_heartbeat():
+ """Returns true"""
+ return make_json_response(None)
+
+
+@views.route("/meta/members")
+def meta_members():
+ team_members = ['Zawlin', 'Xue Si', 'Shi Qing', 'Chen Hui']
+ return make_json_response(team_members)
+
+
+@views.route("/users", methods=['POST'])
+def users():
+ to_serialize = {'status': False}
+ payload = request.get_json()
+ if payload and 'token' in payload:
+ token_str = payload['token']
+ code = 200
+ if not is_token_valid(token_str):
+ to_serialize['status'] = False
+ to_serialize['error'] = 'Invalid authentication token.'
+ else:
+ token = Token.objects(token=token_str).first()
+ data = json.loads(token.data)
+ pk = data['pk']
+ user = User.objects(pk=ObjectId(pk)).first()
+ result = {'username': user.username, 'fullname': user.fullname, 'age': user.age}
+ to_serialize['status'] = True
+ to_serialize['result'] = json.dumps(result)
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/users/register", methods=['POST'])
+def users_register():
+ # todo:remove plain text password storage
+ #
+ # print request.args # for get
+ # print request.form # for post
+ SALT = current_app.config.get('SALT')
+ username, fullname, age, password = None, None, None, None
+ payload = request.get_json()
+ current_app.logger.info(payload)
+ if payload and \
+ 'password' in payload and \
+ 'username' in payload and \
+ 'fullname' in payload and \
+ 'age' in payload:
+ username = payload['username']
+ password = payload['password']
+ fullname = payload['fullname']
+ age = payload['age']
+ to_serialize = {'status': False}
+ code = 200
+ if username is None or fullname is None or age is None or password is None:
+ to_serialize['error'] = 'Required parameter is missing'
+ elif User.objects(username=username).first() is not None:
+ to_serialize['error'] = 'Username already exists'
+ else:
+ to_serialize['status'] = True
+ # note our 'salt' is actually salt+username for extra safety
+ hashed_password = hashlib.sha512(password + SALT + username).hexdigest()
+ User(username=username, hashed_password=hashed_password, fullname=fullname, age=age).save()
+ code = 201
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+ # return make_json_response(ENDPOINT_LIST)
+
+
+@views.route("/users/authenticate", methods=['POST'])
+def users_authenticate():
+ SALT = current_app.config.get('SALT')
+ payload = request.get_json()
+ username = None
+ password = None
+
+ if payload:
+ if 'username' in payload:
+ username = payload['username']
+ if 'password' in payload:
+ password = payload['password']
+
+ token = None
+
+ to_serialize = {'status': False}
+ code = 200
+ if username is None or password is None:
+ to_serialize['error'] = 'Required parameter is missing'
+ else:
+ hashed_password = hashlib.sha512(password + SALT + username).hexdigest()
+ user = User.objects(hashed_password=hashed_password).first() ##????
+ if user is not None:
+ data = {'pk': str(user.pk), 'ip': request.remote_addr}
+ token = Token(token=str(uuid.uuid4()), data=json.dumps(data))
+ token.save()
+
+ if token is not None:
+ to_serialize['status'] = True
+ to_serialize['result'] = {'token': token.token}
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/users/expire", methods=['POST'])
+def users_expire():
+ payload = request.get_json()
+ if payload and 'token' in payload:
+ token_str = payload['token']
+ to_serialize = {'status': False}
+ code = 200
+ if not is_token_valid(token_str):
+ to_serialize['status'] = False
+ else:
+ token = Token.objects(token=token_str).first()
+ token.delete()
+ to_serialize['status'] = True
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/diary")
+def diary():
+ to_serialize = {'status': False}
+ code = 200
+ results = Diary.objects(public=True)
+ result = []
+ for oneresult in results:
+ diary1 = {'id': oneresult.id, 'title': oneresult.title, 'author': oneresult.username,
+ 'publish_date': oneresult.published_time, 'public': oneresult.public, 'text': oneresult.text}
+ result.append(json.dumps(diary1))
+ to_serialize['status'] = True
+ to_serialize['result'] = result
+
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/diary", methods=['POST'])
+def diary_post():
+ to_serialize = {'status': False}
+ payload = request.get_json()
+ if payload:
+ token_str = payload['token']
+ else:
+ token_str = payload
+ code = 200
+ if is_token_valid(token_str) == False:
+ to_serialize['status'] = False
+ to_serialize['error'] = 'Invalid authentication token.'
+ else:
+ token = Token.objects(token=token_str).first()
+ data = json.loads(token.data)
+ pk = data['pk']
+ user = User.objects(pk=ObjectId(pk)).first()
+ username = user.username
+ results = Diary.objects(username=username)
+ result = []
+ if results is not None:
+ for oneresult in results:
+ diary = {'id': oneresult.id, 'title': oneresult.title, 'author': oneresult.username,
+ 'publish_date': oneresult.published_time, 'public': oneresult.public, 'text': oneresult.text}
+ result.append(json.dumps(diary))
+ to_serialize['status'] = True
+ to_serialize['result'] = result
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/diary/create", methods=['POST'])
+def diary_creation():
+ to_serialize = {'status': False}
+ title,text,public,token=None,None,None,None
+ payload = request.get_json()
+ payload2 = request.get_json()
+ if payload2 and \
+ 'title' in payload2 and \
+ 'text' in payload2 and \
+ 'public' in payload2:
+ title = payload2['title']
+ text = payload2['text']
+ public = payload2['public']
+
+ if payload:
+ token_str = payload['token']
+ else:
+ token_str = payload
+ code = 200
+ if is_token_valid(token_str) == False:
+ to_serialize['status'] = False
+ to_serialize['error'] = 'Invalid authentication token.'
+ else:
+ if title is None or text is None or public is None:
+ to_serialize['error'] = 'Required parameter is missing'
+ else:
+ token = Token.objects(token=token_str).first()
+ data = json.loads(token.data)
+ pk = data['pk']
+ user = User.objects(pk=ObjectId(pk)).first()
+ username = user.username
+ dtnow = datetime.datetime.now()
+ published_time = dtnow.replace(microsecond=0).isoformat()
+
+ diary = Diary(title=title, username=username, published_time=published_time, public=public, text=text)
+ diary.save()
+ id=diary.id
+ to_serialize['status'] = True
+ to_serialize['result'] = {'id': id}
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+
+ )
+ return response
+
+
+@views.route("/diary/delete", methods=['POST'])
+def diary_delete():
+ to_serialize = {'status': False}
+ payload = request.get_json()
+ payload2 = request.get_json()
+ if payload2 and \
+ 'id' in payload2:
+ id = payload2['id']
+
+
+ if payload:
+ token_str = payload['token']
+ else:
+ token_str = payload
+ code = 200
+ if is_token_valid(token_str) == False:
+ to_serialize['status'] = False
+ to_serialize['error'] = 'Invalid authentication token.'
+ else:
+ if id is None:
+ to_serialize['error'] = 'Required parameter is missing'
+ else:
+ token = Token.objects(token=token_str).first()
+ data = json.loads(token.data)
+ pk = data['pk']
+ user = User.objects(pk=ObjectId(pk)).first()
+ username = user.username
+ diary = Diary.objects(id=id).first()
+ DiaryOwner = diary.username
+ if DiaryOwner == username:
+ diary.delete()
+ to_serialize['status'] = True
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/diary/permission", methods=['POST'])
+def diary_permission():
+ to_serialize = {'status': False}
+ payload = request.get_json()
+ payload2 = request.get_json()
+ if payload2 and \
+ 'id' in payload2 and \
+ 'public' in payload2:
+
+ id = payload2['id']
+ public = payload2['public']
+
+ if payload:
+ token_str = payload['token']
+ else:
+ token_str = payload
+ code = 200
+ if is_token_valid(token_str) == False:
+ to_serialize['status'] = False
+ to_serialize['error'] = 'Invalid authentication token.'
+ else:
+ if id is None or public is None:
+ to_serialize['error'] = 'Required parameter is missing'
+ else:
+ token = Token.objects(token=token_str).first()
+ data = json.loads(token.data)
+ pk = data['pk']
+ user = User.objects(pk=ObjectId(pk)).first()
+ username = user.username
+ diary = Diary.objects(id=id).first()
+ DiaryOwner = diary.username
+ if DiaryOwner == username:
+ diary.update(public=public)
+ to_serialize['status'] = True
+
+ # todo make the json_response() better
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/debug/resetdb")
+def debug_resetdb():
+ to_serialize = {'status': 'success'}
+ User.drop_collection()
+ Token.drop_collection()
+ Diary.drop_collection()
+ code = 200
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
+
+
+@views.route("/debug/rawdb")
+def debug_getrawdb():
+ to_serialize = {'status': 'success'}
+ to_serialize['users'] = [db_object_to_dict(usr) for usr in User.objects()]
+ to_serialize['tokens'] = [db_object_to_dict(token) for token in Token.objects()]
+ to_serialize['diaries'] = [db_object_to_dict(diary) for diary in Diary.objects()]
+ code = 200
+ response = current_app.response_class(
+ response=json.dumps(to_serialize),
+ status=code,
+ mimetype='application/json'
+ )
+ return response
diff --git a/test.sh b/test.sh
new file mode 100755
index 0000000..af04b2e
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+set -e
+sudo docker-compose -f docker-compose-test.yml -p test build
+
+sudo docker-compose -f docker-compose-test.yml -p test run tests python drop_db.py
+sudo docker-compose -f docker-compose-test.yml -p test run tests python -m py.test --cov=src/service/ tests
+sudo docker stop test_app_1 test_mongodb_1
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..aa74ac1
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,21 @@
+import pytest
+import json
+from src.service.app import create_app
+from flask_mongoengine import MongoEngine
+from mongoengine import connect
+
+
+
+
+@pytest.fixture(scope='session')
+def app():
+
+ # db = connect('mongodb')
+ # db.drop_database('db_test')
+ # db.close()
+ app = create_app(
+ MONGODB_SETTINGS={'db': 'db_test','host':'mongodb'},
+ TESTING=True,
+ SALT='IfHYBwi5ZUFZD9VaonnK',
+ )
+ return app
diff --git a/tests/test_diary_empty.py b/tests/test_diary_empty.py
new file mode 100644
index 0000000..879ae50
--- /dev/null
+++ b/tests/test_diary_empty.py
@@ -0,0 +1,132 @@
+import pytest
+import json
+from flask import url_for
+from src.service.models import Diary
+
+# from flask import current_app as app
+# from src.service.models import User, Token, Diary
+
+from utils import send_post_data, send_post
+from flask_mongoengine import MongoEngine
+from mongoengine import connect
+@pytest.mark.usefixtures('client_class')
+class TestDiaryEmpty(object):
+
+ @classmethod
+ def setup_class(cls):
+
+ db = connect('db_test',host='mongodb')
+ db.drop_database('db_test')
+ db.close()
+ # Diary.drop_collection()
+ # Token.drop_collection()
+ # User.drop_collection()
+ pass
+ # db = connect('mongodb')
+ # db.drop_database('db_test')
+ # db.close()
+ def test_diary_get_empty(self):
+ diary = Diary.objects(id=999).first()
+ if diary:
+ diary.delete()
+ response = self.client.get(url_for('views.diary'))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ assert len(data['result']) == 0
+
+ def test_diary_post_no_token(self):
+ response = send_post(self.client,url_for('views.diary'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+
+ # assert not data['status']
+ # assert 'Invalid authentication token' in data['error']
+
+ def test_diary_post_invalid_token(self):
+ response = send_post_data(self.client,url_for('views.diary'), data=dict(token="e7326198-7055-4559-8d2b-b4568855211e"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Invalid authentication token' in data['error']
+
+ def test_diary_create_no_token(self):
+ response = send_post(self.client,url_for('views.diary_creation'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+
+ # assert not data['status']
+ # assert 'Invalid authentication token' in data['error']
+
+ def test_diary_create_invalid_token(self):
+ response = send_post_data(self.client,url_for('views.diary_creation'), data=dict(token="e7326198-7055-4559-8d2b-b4568855211e"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Invalid authentication token' in data['error']
+
+ def test_diary_delete_no_token(self):
+ response = send_post(self.client,url_for('views.diary_delete'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+
+ # assert not data['status']
+ # assert 'Invalid authentication token' in data['error']
+
+ def test_diary_delete_invalid_token(self):
+ response = send_post_data(self.client,url_for('views.diary_delete'), data=dict(token="e7326198-7055-4559-8d2b-b4568855211e"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Invalid authentication token' in data['error']
+
+ def test_diary_permission_no_token(self):
+ response = send_post(self.client,url_for('views.diary_permission'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+
+ # assert not data['status']
+ # assert 'Invalid authentication token' in data['error']
+
+ def test_diary_permission_invalid_token(self):
+ response = send_post_data(self.client,url_for('views.diary_permission'), data=dict(token="e7326198-7055-4559-8d2b-b4568855211e"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Invalid authentication token' in data['error']
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/test_diary_nonempty.py b/tests/test_diary_nonempty.py
new file mode 100644
index 0000000..df1b271
--- /dev/null
+++ b/tests/test_diary_nonempty.py
@@ -0,0 +1,242 @@
+import pytest
+import json
+import hashlib
+import datetime
+from flask import url_for
+from flask import current_app as app
+from src.service.models import User, Token, Diary
+from utils import send_post_data
+
+from flask_mongoengine import MongoEngine
+from mongoengine import connect
+user1 = "user1"
+user1pw = "password1"
+user1name = "user1"
+user1age = "1"
+
+user2 = "user2"
+user2pw = "password2"
+user2name = "user2"
+user2age = "2"
+
+diary_time = datetime.datetime.now().isoformat()
+diary_public_id = None
+diary_public_title = 'Public title'
+diary_public_text = 'Public text'
+
+diary_private_id = 222
+diary_private_title = 'Private title'
+diary_private_text = 'Private text'
+
+token1uuid = "9cbf0381-38f0-46e3-8709-831e7ecbdd2e"
+token2uuid = "a3a95081-a9af-4122-91cf-1804dbe8ad01"
+expired_token = "2f1830bb-46d9-4df4-b456-93d3c15c9198"
+localhost = '127.0.0.1'
+
+
+def add_user(username, name, age, pw):
+ #SALT = app.config.get('SALT')
+ SALT='IfHYBwi5ZUFZD9VaonnK'
+ hash_password = hashlib.sha512(pw + SALT + username).hexdigest()
+ User(username=username, hashed_password=hash_password, fullname=name, age=age).save()
+ user = User.objects(username=username).first()
+ return str(user.pk)
+
+
+def add_token(token_str, data, expired=False):
+ token = Token(token=token_str, data=json.dumps(data), isexpired=expired)
+ token.save()
+
+
+def add_diary( title, username, published_time, public, text):
+ diary = Diary(title=title, username=username, published_time=published_time, public=public, text=text)
+ diary.save()
+ #diary_public_id=diary.id
+ return diary.id
+
+
+def delete_user(username):
+ user = User.objects(username=username).first()
+ user.delete()
+
+
+def delete_token(token_str):
+ token = Token.objects(token=token_str).first()
+ if token:
+ token.delete()
+
+
+def delete_diary(diary_id):
+ diary = Diary.objects(id=diary_id).first()
+ if diary:
+ diary.delete()
+
+
+@pytest.mark.usefixtures('client_class')
+class TestDiaryNonEmpty(object):
+ @classmethod
+ def setup_class(cls):
+
+ db = connect('db_test',host='mongodb')
+ db.drop_database('db_test')
+ db.close()
+ global diary_public_id,diary_private_id
+ user1id = add_user(user1, user1name, user1age, user1pw)
+ data = {'pk': user1id, 'ip': localhost}
+ add_token(token1uuid, data)
+ add_token(expired_token, data, True)
+
+ user2id = add_user(user2, user2name, user2age, user2pw)
+ data = {'pk': user2id, 'ip': localhost}
+ add_token(token2uuid, data)
+
+ diary_public_id=add_diary( diary_public_title, user1, diary_time, True, diary_public_text)
+ diary_private_id=add_diary( diary_private_title, user1, diary_time, False, diary_private_text)
+
+ @classmethod
+ def teardown_class(cls):
+ delete_user(user1)
+ delete_user(user2)
+
+ delete_token(token1uuid)
+ delete_token(expired_token)
+ delete_token(token2uuid)
+
+ delete_diary(diary_public_id)
+ delete_diary(diary_private_id)
+
+ def test_diary_get(self):
+ response = self.client.get(url_for('views.diary'))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ assert len(data['result']) == 1
+
+ diary_data = json.loads(data['result'][0])
+ assert diary_data['id'] == int(diary_public_id)
+ assert diary_data['title'] == diary_public_title
+ assert diary_data['author'] == user1
+ assert diary_data['publish_date'] == diary_time
+ assert diary_data['public']
+ assert diary_data['text'] == diary_public_text
+
+ def test_diary_post_owner(self):
+ response = send_post_data(self.client,url_for('views.diary'),
+ data=dict(token=token1uuid))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ assert len(data['result']) == 2
+
+ diary_data = json.loads(data['result'][1])
+ assert diary_data['id'] == int(diary_private_id)
+ assert diary_data['title'] == diary_private_title
+ assert diary_data['author'] == user1
+ assert diary_data['publish_date'] == diary_time
+ assert not diary_data['public']
+ assert diary_data['text'] == diary_private_text
+
+ def test_diary_post_not_owner(self):
+ response = send_post_data(self.client,url_for('views.diary'),
+ data=dict(token=token2uuid))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ assert len(data['result']) == 0
+
+ def test_diary_create_success(self):
+ response = send_post_data(self.client,url_for('views.diary_creation'),
+ data=dict(token=token2uuid,title=diary_public_title,text=diary_public_text,public=True))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+ assert 'id' in data['result']
+
+ assert data['status']
+ assert data['result']['id'] == 3
+
+ delete_diary(data['result']['id'])
+
+ def test_diary_create_error(self):
+ response = send_post_data(self.client,url_for('views.diary_creation'),
+ data=dict(token=token2uuid))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+
+ def test_diary_delete_not_owner(self):
+ response = send_post_data(self.client,url_for('views.diary_delete'),
+ data=dict(token=token2uuid, id=diary_private_id))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert not data['status']
+
+ def test_diary_delete_owner(self):
+ diary_id = add_diary("test_diary_delete", user2, diary_time, True, "user2 owner")
+ response = send_post_data(self.client,url_for('views.diary_delete'),
+ data=dict(token=token2uuid, id=diary_id))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert data['status']
+
+ diary = Diary.objects(id=999).first()
+ assert not diary
+
+ def test_diary_permission_not_owner(self):
+ response = send_post_data(self.client,url_for('views.diary_permission'),
+ data=dict(token=token2uuid, id=diary_private_id, public=True))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert not data['status']
+
+ diary = Diary.objects(id=diary_private_id).first()
+ assert not diary.public
+
+ def test_diary_permission_owner_private_to_public(self):
+ response = send_post_data(self.client,url_for('views.diary_permission'),
+ data=dict(token=token1uuid, id=diary_private_id, public=True))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert data['status']
+
+ diary = Diary.objects(id=diary_private_id).first()
+ assert diary.public
+
+ def test_diary_permission_owner_public_to_private(self):
+ response = send_post_data(self.client,url_for('views.diary_permission'),
+ data=dict(token=token1uuid, id=diary_public_id, public=False))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert data['status']
+
+ diary = Diary.objects(id=diary_public_id).first()
+ assert not diary.public
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/test_example.py b/tests/test_example.py
new file mode 100644
index 0000000..c9ed82e
--- /dev/null
+++ b/tests/test_example.py
@@ -0,0 +1,20 @@
+import pytest
+import json
+from flask import Flask, url_for
+from src.service.views import ENDPOINT_LIST
+
+
+def test_get_index(client):
+ page = client.get(url_for('views.index')) # can use the endpoint(method) name here
+ assert page.status_code == 200 # response code
+
+ data = json.loads(page.data) # response data
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ assert data['result'] == ENDPOINT_LIST
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/test_meta.py b/tests/test_meta.py
new file mode 100644
index 0000000..2781c4b
--- /dev/null
+++ b/tests/test_meta.py
@@ -0,0 +1,28 @@
+import pytest
+import json
+from flask import url_for
+
+
+def test_meta_heartbeat(client):
+ page = client.get(url_for('views.meta_heartbeat'))
+ assert page.status_code == 200
+
+ data = json.loads(page.data)
+ assert 'status' in data
+ assert data['status']
+
+
+def test_meta_members(client):
+ page = client.get(url_for('views.meta_members'))
+ assert page.status_code == 200
+
+ data = json.loads(page.data)
+ assert 'status' in data
+ assert 'result' in data
+
+ assert data['status']
+ assert data['result'] == ['Zawlin', 'Xue Si', 'Shi Qing', 'Chen Hui']
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/test_users_empty.py b/tests/test_users_empty.py
new file mode 100644
index 0000000..1622a5e
--- /dev/null
+++ b/tests/test_users_empty.py
@@ -0,0 +1,205 @@
+import pytest
+import json
+from flask import url_for
+from src.service.models import User
+import urllib2
+from utils import send_post_data, send_post
+
+from flask_mongoengine import MongoEngine
+from mongoengine import connect
+@pytest.mark.usefixtures('client_class')
+class TestUsersEmpty(object):
+
+ @classmethod
+ def setup_class(self):
+ db = connect('db_test',host='mongodb')
+ db.drop_database('db_test')
+ db.close()
+
+
+ @classmethod
+ def teardown_class(self):
+ pass
+
+ def test_users_no_token(self):
+ response = send_post(self.client,
+ url_for('views.users'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+ #
+ # assert not data['status']
+ # assert 'Invalid authentication token' in data['error']
+
+ def test_users_invalid_token(self):
+ response = send_post_data(self.client,
+ url_for('views.users'),
+ dict(token="b563fdc7-1c1c-46d8-a7a0-42ea1f1d9c4d"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Invalid authentication token' in data['error']
+
+ def test_user_register_no_args(self):
+ response = send_post(self.client,
+ url_for('views.users_register'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+ #
+ # assert not data['status']
+ # assert 'Required parameter is missing' in data['error']
+
+ def test_user_register_no_username(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(password="2", fullname="3", age="4"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_register_no_password(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(username="1", fullname="3", age="4"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_register_no_fullname(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(username="1", password="2", age="4"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_register_no_age(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(username="1", password="2", fullname="3"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_register_success(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(username="1", password="2", fullname="3", age="4"))
+ assert response.status_code == 201
+
+ data = json.loads(response.data)
+ assert 'error' not in data
+ assert 'status' in data
+
+ assert data['status']
+
+ # delete user
+ user = User.objects(username="1").first()
+ user.delete()
+ assert not User.objects(username="1").first()
+
+ def test_user_authenticate_no_args(self):
+ response = send_post(self.client,
+ url_for('views.users_authenticate'))
+ assert response.status_code == 400
+
+ # data = json.loads(response.data)
+ # assert 'error' in data
+ # assert 'status' in data
+ #
+ # assert not data['status']
+ # assert 'Required parameter is missing' in data['error']
+
+ def test_user_authenticate_no_username(self):
+ response = send_post_data(self.client,
+ url_for('views.users_authenticate'),
+ dict(password="2"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_authenticate_no_password(self):
+ response = send_post_data(self.client,
+ url_for('views.users_authenticate'),
+ dict(username="1"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Required parameter is missing' in data['error']
+
+ def test_user_authenticate_valid_args_no_token(self):
+ response = send_post_data(self.client,
+ url_for('views.users_authenticate'),
+ dict(username="1", password="2"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' not in data
+ assert 'status' in data
+
+ assert not data['status']
+
+ def test_users_expire_no_token(self):
+ response = send_post(self.client,
+ url_for('views.users_expire'))
+ assert response.status_code == 400
+ #
+ # data = json.loads(response.data)
+ # assert 'error' not in data
+ # assert 'status' in data
+ #
+ # assert not data['status']
+
+ def test_users_expire_invalid_token(self):
+ response = send_post_data(self.client,
+ url_for('views.users_expire'),
+ dict(token="b563fdc7-1c1c-46d8-a7a0-42ea1f1d9c4d"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' not in data
+ assert 'status' in data
+
+ assert not data['status']
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/test_users_nonempty.py b/tests/test_users_nonempty.py
new file mode 100644
index 0000000..34480f0
--- /dev/null
+++ b/tests/test_users_nonempty.py
@@ -0,0 +1,130 @@
+import pytest
+import json
+import hashlib
+from flask import url_for
+#from src.service.app import SALT
+from flask import current_app as app
+from src.service.models import User, Token, is_token_valid
+from utils import send_post_data
+user1 = "user1"
+user1pw = "password1"
+user1name = "user1"
+user1age = "1"
+token1uuid = "f7d86d6c-2c13-47b2-8d45-3da9cf943fc9"
+expired_token = "e7326198-7055-4559-8d2b-b4568855211e"
+localhost = '127.0.0.1'
+
+from flask_mongoengine import MongoEngine
+from mongoengine import connect
+
+@pytest.mark.usefixtures('client_class')
+class TestUsersNonEmpty(object):
+ @classmethod
+ def setup_class(cls):
+
+ db = connect('db_test',host='mongodb')
+ db.drop_database('db_test')
+ db.close()
+ # db = connect('mongodb')
+ # db.drop_database('db_test')
+ # db.close()
+ # SALT = app.config.get('SALT')
+ # print SALT
+ SALT='IfHYBwi5ZUFZD9VaonnK'
+ hash_password = hashlib.sha512(user1pw + SALT + user1).hexdigest()
+ User(username=user1, hashed_password=hash_password, fullname=user1name, age=user1age).save()
+ user = User.objects(username=user1).first()
+ userid = str(user.pk)
+
+ data = {'pk': userid, 'ip': localhost}
+ token = Token(token=token1uuid, data=json.dumps(data))
+ token.save()
+
+ token = Token(token=expired_token, data=json.dumps(data), isexpired=True)
+ token.save()
+
+ @classmethod
+ def teardown_class(cls):
+ user = User.objects(username=user1).first()
+ user.delete()
+
+ token = Token.objects(token=token1uuid).first()
+ if token:
+ token.delete()
+
+ token = Token.objects(token=expired_token).first()
+ if token:
+ token.delete()
+
+ def test_users_valid_token(self):
+ response = send_post_data(self.client,
+ url_for('views.users'),
+ dict(token=token1uuid))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'result' in data
+ assert 'status' in data
+
+ assert data['status']
+ user_data = json.loads(data['result'])
+ assert user_data['username'] == user1
+ assert user_data['fullname'] == user1name
+ assert user_data['age'] == int(user1age)
+
+ def test_users_register_username_exist(self):
+ response = send_post_data(self.client,
+ url_for('views.users_register'),
+ dict(username=user1, password="2", fullname="3", age="4"))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'error' in data
+ assert 'status' in data
+
+ assert not data['status']
+ assert 'Username already exists' in data['error']
+
+ def test_users_authenticate_success(self):
+ response = send_post_data(self.client,
+ url_for('views.users_authenticate'),
+ dict(username=user1, password=user1pw,fullname=user1name,age=user1age))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert 'result' in data
+ assert 'token' in data['result']
+
+ assert data['status']
+ token_str = data['result']['token']
+ assert is_token_valid(token_str)
+
+ token = Token.objects(token=token_str).first()
+ token.delete()
+ assert not Token.objects(token=token_str).first()
+
+ def test_users_expire_token_success(self):
+ response = send_post_data(self.client,
+ url_for('views.users_expire'),
+ dict(token=token1uuid))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ print data['status']
+ assert 'status' in data
+ assert data['status']
+
+ def test_users_expire_expired_token(self):
+ response = send_post_data(self.client,
+ url_for('views.users_expire'),
+ dict(token=expired_token))
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert 'status' in data
+ assert not data['status']
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/tests/tests.py b/tests/tests.py
new file mode 100644
index 0000000..c9978a2
--- /dev/null
+++ b/tests/tests.py
@@ -0,0 +1 @@
+print "Doing nothing"
diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644
index 0000000..af515d3
--- /dev/null
+++ b/tests/utils.py
@@ -0,0 +1,14 @@
+import json
+
+
+def send_post_data(client, endpoint, data):
+ return client.post(endpoint,
+ data=json.dumps(data),
+ content_type='application/json',
+ environ_base={'REMOTE_ADDR': '127.0.0.1'})
+
+
+def send_post(client, endpoint):
+ return client.post(endpoint,
+ content_type='application/json',
+ environ_base={'REMOTE_ADDR': '127.0.0.1'})