Commit f867edb11e372a8dc06e4236e6829f76f62bf818
- Diff rendering mode:
- inline
- side by side
README.md
(61 / 25)
  | |||
8 | 8 | ------------ | |
9 | 9 | ||
10 | 10 | This is the sweet store application. | |
11 | |||
12 | 11 | The store for the decentralized, semantic, social web tweets a.k.a SWeeTs! | |
13 | 12 | ||
13 | This README is about installing, configuring and running/deploying this | ||
14 | application. If you want to know more about SWeeTs, please go to | ||
15 | [wiki.janastu.org/Sweet_Web](http://janastu.org/technoscience/index.php/Sweet_Web) and | ||
16 | [trac.pantoto.org/sweet-web](http://trac.pantoto.org/sweet-web). | ||
17 | |||
14 | 18 | This application acts as the repository store for all the SWeeTs that are | |
15 | generated from the clients registered with the sweet store. It also provides | ||
19 | generated from the clients registered with the sweet store. It provides | ||
16 | 20 | query APIs to query the SWeeTs. | |
17 | 21 | ||
22 | It also provides user management to manage the users of the swtstore. | ||
23 | |||
24 | All the APIs of the swtstore are accessed by using an access token which is | ||
25 | generated by the swtstore when an user authorizes a third-party application | ||
26 | through OAuth. | ||
27 | |||
18 | 28 | Sweet store provides the following APIs: | |
19 | 29 | ||
20 | 30 | - [GET] /api/sweets/<id>: Get a specific SWeeT by its id. | |
21 | 31 | ||
32 | - [GET] /api/sweets/q?who=<username>&what=<contextname>&where=<URL> : | ||
33 | This API is for querying sweet based on the who, what and where | ||
34 | parameters. | ||
35 | This API do not support querying based on parameters mentioned in how, | ||
36 | but will be supported in future. Right now, the client can get sweets | ||
37 | based on the above mentioned three parameters, and as the 'how' part is | ||
38 | a JSON, it is trivial to do further filtering based on parameters of | ||
39 | 'how' by the client. | ||
40 | |||
22 | 41 | - [POST] /api/sweets : Post a SWeeT to this swtstore with the data in the | |
23 | body of the request. Only registered applications can sweet to sweet store. | ||
42 | body of the request. The data or payload is a list of sweets. Even if you | ||
43 | are sending one sweet, make sure that the sweet is in a list. | ||
24 | 44 | ||
25 | - [POST] /api/context : Create a new context on the swtstore. | ||
45 | - [GET] /api/users/me : Get a JSON details of the current user logged in. | ||
26 | 46 | ||
27 | 47 | ||
28 | Any client side application can communicate with the sweet store using these | ||
29 | APIs. | ||
48 | Any third-party client side application can communicate with the swtstore | ||
49 | using these APIs, provided they have a valid access token. | ||
30 | 50 | ||
31 | 51 | ||
32 | 52 | Installing | |
… | … | ||
62 | 62 | For more information on supported databases see | |
63 | 63 | [here](http://docs.sqlalchemy.org/en/rel_0_9/dialects/index.html). | |
64 | 64 | ||
65 | _Important:_ | ||
66 | __So once you are sure you have Python and a relational database (like | ||
67 | MySQL/Postgresql etc.) installed. You can go ahead and follow these steps:__ | ||
65 | ___ Once you are sure you have Python and a relational database (like | ||
66 | MySQL/Postgresql etc.) installed. You can go ahead and follow these steps:___ | ||
68 | 67 | ||
69 | * Clone the repository from [https://git.pantoto.org/sweet-web/sweet-web-engine] | ||
70 | (https://git.pantoto.org/sweet-web/sweet-web-engine) OR you can download the | ||
68 | * Clone the repository from [https://git.pantoto.org/sweet-web/sweet-web-engine](https://git.pantoto.org/sweet-web/sweet-web-engine) | ||
69 | OR you can download the | ||
71 | 70 | code from the same link. | |
72 | 71 | ||
73 | * Initialize a python virtual environment using virtualenv in the same place | ||
74 | where you cloned the reposiory in the above step. Now, activate the | ||
75 | environment ``$ source <path/to/your/current-virtual-env>/bin/activate `` | ||
72 | * It is strongly recommended to do the installation inside a virtual environment. | ||
73 | If you think, you know what you are doing and don't need the virtual | ||
74 | environment, you can skip to the next step. | ||
75 | Initialize a python virtual environment using `virtualenv` in the same directory | ||
76 | where you cloned the repository in the above step. Now, activate the | ||
77 | environment | ||
76 | 78 | ||
77 | See | ||
78 | [http://www.virtualenv.org/en/latest/virtualenv.html] | ||
79 | (http://www.virtualenv.org/en/latest/virtualenv.html) for more details. | ||
79 | > ``$ source <path/to/your/current-virtual-env>/bin/activate `` | ||
80 | 80 | ||
81 | See [http://www.virtualenv.org/en/latest/virtualenv.html](http://www.virtualenv.org/en/latest/virtualenv.html) for more details about `virtualenv`. | ||
82 | |||
81 | 83 | * Run the setup.py script to install `` python setup.py install `` | |
82 | 84 | ||
83 | 85 | You're done installing swtstore. Now you need to configure it to run. | |
… | … | ||
91 | 91 | * Copy the contents of ``sample_config.py`` inside the ``swtstore`` directory | |
92 | 92 | into ``config.py`` inside ``swtstore`` directory itself. | |
93 | 93 | ||
94 | Assuming you are using a Unix based system, and you are in the root directory | ||
94 | Assuming you are using a *-nix based system, and you are in the root directory | ||
95 | 95 | of the codebase, | |
96 | 96 | ||
97 | 97 | `` $ cp swtstore/sample_config.py swtstore/config.py`` | |
98 | 98 | ||
99 | 99 | * Edit the config.py file, and change the values accordingly. | |
100 | 100 | ||
101 | * Now, you have to setup the database for the swtstore application. But | ||
102 | fortunately, the creation of database and tables have also been scripted, so | ||
103 | all you need to do is run the ``dbsetup.py`` script. | ||
104 | `` $ python dbsetup.py `` | ||
101 | 105 | ||
106 | **NOTE:** Please remember that all these configuration step is necessary and is | ||
107 | required wether you are running the application locally or deploying it on a | ||
108 | server. | ||
102 | 109 | ||
110 | |||
111 | |||
103 | 112 | Running the server locally | |
104 | 113 | -------------------------- | |
105 | 114 | ||
106 | 115 | Run the runserver.py script to run the server locally, | |
107 | 116 | ||
108 | `` python runserver.py `` | ||
117 | > `` $ python runserver.py `` | ||
109 | 118 | ||
110 | This runs the application locally, on port 5001 | ||
119 | This runs the application locally, on port 5001. So you can direct your browser | ||
120 | to http://localhost:5001 | ||
111 | 121 | ||
112 | 122 | ||
113 | 123 | ||
114 | 124 | Deploying the application | |
115 | 125 | ------------------------- | |
116 | 126 | ||
117 | The wsgi script to deploy the application is present. | ||
118 | Point your webserver like Apache, or Nginx to point to the swtstore.wsgi | ||
127 | SwtStore is deployed as a WSGI application server. | ||
128 | |||
129 | The wsgi script to deploy the application is provided (its called | ||
130 | `swtstore.wsgi`). | ||
131 | Point your webserver like Apache, or Nginx to point to the `swtstore.wsgi` | ||
119 | 132 | script. | |
120 | 133 | ||
121 | 134 | See Apache WSGI configuration here: | |
122 | [http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIScriptAlias.html] | ||
123 | (http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIScriptAlias.html) | ||
135 | [http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIScriptAlias.html](http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIScriptAlias.html) | ||
124 | 136 | ||
137 | TODO: [insert Nginx WSGI config link] | ||
125 | 138 | ||
139 | |||
126 | 140 | Help / Feedback | |
127 | 141 | --------------- | |
128 | 142 | ||
129 | 143 | If you need any help, or have any questions, comments or feedback, you can contact at | |
130 | rayanon or arvind or bhanu @servelots.com | ||
144 | rayanon or arvind or bhanu at servelots.com | ||
131 | 145 | ||
132 | 146 | You can also join channel #servelots on freenode network, using your favourite | |
133 | 147 | IRC client. We usually hang out at #servelots. |
dbsetup.py
(10 / 3)
  | |||
1 | # coding utf-8 | ||
1 | # -*- coding: utf-8 -*- | ||
2 | # swtstore->dbsetup.py | ||
2 | 3 | ||
4 | # Create and setup databases for the first time run of the application | ||
5 | |||
3 | 6 | import sys, os | |
4 | 7 | ||
8 | # Get the path to the base directory of the app | ||
5 | 9 | BASE_DIR = os.path.join(os.path.dirname(__file__)) | |
6 | 10 | ||
11 | # append the path to the WSGI env path | ||
7 | 12 | sys.path.insert(0, BASE_DIR) | |
8 | 13 | ||
14 | # Import and create the app; also get the db instance from the current app | ||
9 | 15 | from swtstore import create_app, getDBInstance | |
10 | 16 | ||
11 | 17 | app = create_app() | |
12 | 18 | ||
13 | 19 | db = getDBInstance() | |
14 | 20 | ||
15 | # Import all modules which represents a SQLAlchemy model | ||
16 | # They have correspondin tables that are needed to be created | ||
21 | # Import all modules which represents a SQLAlchemy model; | ||
22 | # they have corresponding tables that are needed to be created | ||
17 | 23 | from swtstore.classes.models import Sweet, Context, Client | |
18 | 24 | from swtstore.classes.models.um import User, Group, Membership | |
19 | 25 | ||
26 | # Create them! | ||
20 | 27 | db.create_all() |
runserver.py
(7 / 1)
  | |||
1 | 1 | # -*- coding: utf-8 -*- | |
2 | # swtstore->runserver.py | ||
3 | |||
2 | 4 | # Script to run the application server in development mode | |
3 | 5 | ||
4 | 6 | import sys, os | |
5 | from swtstore import create_app, getDBInstance | ||
6 | 7 | ||
7 | 8 | # Get the path to the base directory of the app | |
8 | 9 | BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) | |
… | … | ||
11 | 11 | # append the path to the WSGI env path | |
12 | 12 | sys.path.insert(0, BASE_DIR) | |
13 | 13 | ||
14 | # Import and create the app | ||
15 | from swtstore import create_app | ||
16 | |||
14 | 17 | app = create_app() | |
15 | 18 | ||
19 | # Run the server if this script is directly executed | ||
20 | # Presumably, this is development mode | ||
16 | 21 | if __name__ == '__main__': | |
17 | 22 | app.run(debug=True, host='0.0.0.0', port=5001) |
setup.py
(3 / 3)
  | |||
11 | 11 | swtstore | |
12 | 12 | -------- | |
13 | 13 | ||
14 | The sweet store for decentralized, semantic, social web tweets a.k.a SWeeTs!! | ||
14 | The store for decentralized, semantic, social web tweets a.k.a SWeeTs!! | ||
15 | 15 | ||
16 | 16 | """ | |
17 | 17 | from setuptools import setup | |
… | … | ||
30 | 30 | version='0.1 - alpha', | |
31 | 31 | url='https://git.pantoto.org/sweet-web', | |
32 | 32 | license='BSD', | |
33 | author='Halwai', | ||
34 | author_email='rayanon@servelots.com', | ||
33 | author='swtstore authors', | ||
34 | author_email='rayanon004@gmail.com', | ||
35 | 35 | description='Server-side store for decentralized, semantic, social, web\ | |
36 | 36 | tweets', | |
37 | 37 | long_description=__doc__, |
swtstore/application.py
(4 / 4)
  | |||
9 | 9 | from classes.database import db | |
10 | 10 | from config import DefaultConfig | |
11 | 11 | from classes import views | |
12 | #from something import oauth | ||
13 | |||
14 | 12 | #from classes import models | |
13 | from classes import oauth | ||
15 | 14 | ||
16 | 15 | __all__ = ['create_app', 'getDBInstance'] | |
17 | 16 | ||
… | … | ||
21 | 21 | (views.api, '/api'), | |
22 | 22 | (views.user, '/users'), | |
23 | 23 | (views.context, '/contexts'), | |
24 | (views.app, '/apps') | ||
24 | (views.app, '/apps'), | ||
25 | (views.Oauth, '/oauth') | ||
25 | 26 | ) | |
26 | 27 | ||
27 | 28 | ||
… | … | ||
65 | 65 | def configure_extensions(app): | |
66 | 66 | db.init_app(app) | |
67 | 67 | db.app = app | |
68 | #oauth.init_app(app) | ||
68 | oauth.init_app(app) | ||
69 | 69 | ||
70 | 70 | # return the current db instance | |
71 | 71 | # TODO: is this needed so much? |
  | |||
29 | 29 | ||
30 | 30 | _is_private = db.Column(db.Boolean) | |
31 | 31 | ||
32 | _host_url = db.Column(db.String(60)) | ||
33 | |||
32 | 34 | _redirect_uris = db.Column(db.Text) | |
33 | 35 | _default_scopes = db.Column(db.Text) | |
34 | 36 | ||
35 | 37 | ||
36 | 38 | @property | |
39 | def client_id(self): | ||
40 | return self.id | ||
41 | |||
42 | @property | ||
37 | 43 | def client_type(self): | |
38 | 44 | if self._is_private: | |
39 | 45 | return 'private' | |
40 | 46 | return 'public' | |
41 | 47 | ||
42 | 48 | @property | |
49 | def host_url(self): | ||
50 | return self._host_url | ||
51 | |||
52 | @property | ||
43 | 53 | def redirect_uris(self): | |
44 | 54 | if self._redirect_uris: | |
45 | 55 | return self._redirect_uris.split() | |
… | … | ||
66 | 66 | return [] | |
67 | 67 | ||
68 | 68 | def __repr__(self): | |
69 | return '[Client: <%s> : <%s>]' % (self.id, self.name) | ||
69 | return '<Client: %s :: ID: %s>' % (self.name, self.id) | ||
70 | 70 | ||
71 | 71 | def __str__(self): | |
72 | return '[Client: <%s> : <%s>]' % (self.id, self.name) | ||
72 | return '<Client: %s :: ID: %s>' % (self.name, self.id) | ||
73 | 73 | ||
74 | 74 | ||
75 | 75 | # create and persist the client to the database | |
… | … | ||
124 | 124 | """ | |
125 | 125 | The final token to be used by a client | |
126 | 126 | """ | |
127 | |||
128 | __tablename__ = 'tokens' | ||
129 | |||
127 | 130 | id = db.Column(db.Integer, primary_key=True) | |
128 | 131 | ||
129 | 132 | client_id = db.Column(db.String(40), db.ForeignKey('clients.id'), | |
… | … | ||
156 | 156 | ||
157 | 157 | @oauth.clientgetter | |
158 | 158 | def loadClient(client_id): | |
159 | return Client.query.filter_by(id=client_id).first() | ||
159 | print '@oauth.clientgetter' | ||
160 | #return Client.query.filter_by(id=client_id).first() | ||
161 | return Client.query.get(client_id) | ||
160 | 162 | ||
161 | 163 | @oauth.grantgetter | |
162 | 164 | def loadGrant(client_id, code): | |
165 | print '@oauth.grantgetter' | ||
163 | 166 | return Grant.query.filter_by(client_id=client_id, code=code).first() | |
164 | 167 | ||
165 | 168 | @oauth.grantsetter | |
166 | 169 | def saveGrant(client_id, code, request, *args, **kwargs): | |
170 | print '@oauth.grantsetter' | ||
167 | 171 | expires = datetime.utcnow() + timedelta(seconds=100) | |
168 | 172 | grant = Grant( | |
169 | 173 | client_id = client_id, | |
… | … | ||
183 | 183 | ||
184 | 184 | @oauth.tokengetter | |
185 | 185 | def loadToken(access_token=None, refresh_token=None): | |
186 | print '@oauth.tokengetter' | ||
186 | 187 | if access_token: | |
187 | 188 | return Token.query.filter_by(access_token=access_token).first() | |
188 | 189 | elif refresh_token: | |
… | … | ||
191 | 191 | ||
192 | 192 | @oauth.tokensetter | |
193 | 193 | def saveToken(token, request, *args, **kwargs): | |
194 | print '@oauth.tokensetter' | ||
195 | |||
194 | 196 | toks = Token.query.filter_by(client_id=request.client.id, | |
195 | 197 | user_id=request.user.id) | |
196 | 198 | # make sure that every client has only one token connected to a user | |
197 | 199 | for t in toks: | |
198 | 200 | db.session.delete(t) | |
201 | |||
199 | 202 | expires_in = token.pop('expires_in') | |
200 | 203 | expires = datetime.utcnow() + timedelta(seconds=expires_in) | |
201 | 204 | ||
… | … | ||
206 | 206 | access_token = token['access_token'], | |
207 | 207 | refresh_token = token['refresh_token'], | |
208 | 208 | token_type = token['token_type'], | |
209 | _scopes = token['scopes'], | ||
209 | _scopes = token['scope'], | ||
210 | 210 | expires = expires, | |
211 | 211 | client_id = request.client.id, | |
212 | user = request.user.id | ||
212 | user = request.user | ||
213 | 213 | ) | |
214 | 214 | db.session.add(tok) | |
215 | 215 | db.session.commit() | |
216 | 216 | return tok | |
217 | |||
218 | @oauth.usergetter | ||
219 | def getUser(): | ||
220 | return User.getCurrentUser() |
  | |||
50 | 50 | print self.created | |
51 | 51 | return { | |
52 | 52 | 'id': self.id, | |
53 | 'who': self.who, | ||
53 | 'who': self.who.username, | ||
54 | 'user_id': self.user_id, | ||
54 | 55 | 'what': self.what.name, | |
55 | 56 | 'context_id': self.context_id, | |
56 | 57 | 'where': self.where, |
  | |||
1 | 1 | ||
2 | 2 | ||
3 | def make_cross_origin_headers(response): | ||
4 | response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000' | ||
5 | response.headers['Access-Control-Allow-Origin'] = 'http://localhost' | ||
6 | response.headers['Access-Control-Max-Age'] = '20days' | ||
7 | response.headers['Access-Control-Allow-Headers'] = 'Origin,\ | ||
8 | X-Requested-With, Content-Type, Accept' | ||
3 | def make_cross_origin_headers(response, host_url): | ||
4 | print 'client\'s host_url: %s' % host_url | ||
5 | response.headers['Access-Control-Allow-Origin'] = host_url | ||
6 | response.headers['Access-Control-Max-Age'] = '3600' | ||
7 | response.headers['Access-Control-Allow-Credentials'] = 'true' | ||
8 | response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept' | ||
9 | |||
10 | print 'Updated headers' | ||
11 | print response.headers | ||
9 | 12 | ||
10 | 13 | return response |
  | |||
3 | 3 | from .user import user | |
4 | 4 | from .context import context | |
5 | 5 | from .app import app | |
6 | from .oauth import Oauth |
swtstore/classes/views/api.py
(68 / 29)
  | |||
1 | from flask import Module, jsonify, request, make_response, abort, g | ||
2 | import json | ||
1 | from flask import Module, jsonify, request, make_response, abort, g, json | ||
2 | #import json | ||
3 | 3 | from sqlalchemy.exc import IntegrityError | |
4 | 4 | ||
5 | 5 | from swtstore.classes.models import Context | |
… | … | ||
7 | 7 | from swtstore.classes.exceptions import AlreadyExistsError | |
8 | 8 | from swtstore.classes.utils import urlnorm # normalize URLs | |
9 | 9 | from swtstore.classes.utils.httputils import make_cross_origin_headers | |
10 | from swtstore.classes import oauth | ||
10 | 11 | ||
11 | 12 | ||
12 | 13 | api = Module(__name__) | |
13 | 14 | ||
14 | 15 | ||
15 | |||
16 | 16 | # Get a specific sweet | |
17 | 17 | @api.route('/sweets/<int:id>', methods=['GET']) | |
18 | 18 | def getSweetById(id): | |
… | … | ||
30 | 30 | ||
31 | 31 | # Post a sweet to the sweet store | |
32 | 32 | @api.route('/sweets', methods=['OPTIONS', 'POST']) | |
33 | def createSweet(): | ||
33 | @oauth.require_oauth('email', 'sweet') | ||
34 | def createSweet(oauth_request): | ||
34 | 35 | ||
35 | 36 | response = make_response() | |
36 | 37 | ||
38 | client = oauth_request.client | ||
39 | |||
37 | 40 | #TODO: check if response is coming from a registered client | |
38 | response = make_cross_origin_headers(response) | ||
41 | response = make_cross_origin_headers(response, client.host_url) | ||
39 | 42 | ||
40 | 43 | if request.method == 'OPTIONS': | |
41 | 44 | response.status_code = 200 | |
… | … | ||
56 | 56 | print 'new sweet payload recvd..' | |
57 | 57 | print payload | |
58 | 58 | ||
59 | if 'who' not in payload and 'what' not in payload and 'where' not in\ | ||
60 | payload and 'how' not in payload: | ||
59 | # the payload has to be a list; a list of swts | ||
60 | for each in payload: | ||
61 | if 'what' not in each and 'where' not in\ | ||
62 | each and 'how' not in each: | ||
61 | 63 | ||
62 | print 'Invalid Request..' | ||
63 | abort(400) | ||
64 | print 'Invalid Request..' | ||
65 | abort(400) | ||
64 | 66 | ||
65 | #who = User.getUserByName(payload['who']) | ||
67 | # all ok. create swts from the list now | ||
66 | 68 | ||
67 | what = Context.query.filter_by(name=payload['what']).first() | ||
69 | swts = [] | ||
70 | for each in payload: | ||
68 | 71 | ||
69 | if what is None: | ||
70 | print 'Context doesn\'t exist' | ||
71 | g.error = 'Context doesn\'t exist' | ||
72 | abort(400) # this context doesn't exist! | ||
72 | what = Context.query.filter_by(name=each['what']).first() | ||
73 | 73 | ||
74 | print 'SWEET DATA' | ||
75 | print '------------' | ||
76 | print payload['who'] | ||
77 | print what | ||
78 | print payload['where'] | ||
79 | print payload['how'] | ||
80 | print '-------------' | ||
74 | if what is None: | ||
75 | print 'Context doesn\'t exist' | ||
76 | g.error = 'Context doesn\'t exist' | ||
77 | abort(400) # this context doesn't exist! | ||
81 | 78 | ||
82 | new_sweet = Sweet(payload['who'], what, payload['where'], payload['how']) | ||
79 | # Get the authenticated user from the oauth request object. | ||
80 | # Older swtr clients sending `who` in string will be ignored. | ||
81 | who = oauth_request.user | ||
83 | 82 | ||
84 | print new_sweet | ||
85 | new_sweet.persist() | ||
83 | print 'SWEET DATA' | ||
84 | print '------------' | ||
85 | print who | ||
86 | print what | ||
87 | print each['where'] | ||
88 | print each['how'] | ||
89 | print '-------------' | ||
86 | 90 | ||
91 | new_sweet = Sweet(who, what, each['where'], each['how']) | ||
92 | |||
93 | new_sweet.persist() | ||
94 | print new_sweet | ||
95 | swts.append(new_sweet.id) | ||
96 | |||
87 | 97 | response.status_code = 200 | |
98 | response.data = json.dumps(swts) | ||
88 | 99 | return response | |
89 | 100 | ||
90 | 101 | ||
91 | |||
92 | 102 | # The Sweet query API: /sweets/q?who=<>&what=<>&where=<> | |
93 | 103 | # args: who, what, where | |
94 | @api.route('/sweets/q', methods=['GET']) | ||
95 | def querySweets(): | ||
104 | @api.route('/sweets/q', methods=['GET', 'OPTIONS']) | ||
105 | @oauth.require_oauth('sweet') | ||
106 | def querySweets(oauth_request): | ||
96 | 107 | ||
108 | response = make_response() | ||
109 | response = make_cross_origin_headers(response, | ||
110 | oauth_request.client.host_url) | ||
111 | |||
112 | if request.method == 'OPTIONS': | ||
113 | reponse.status_code = 200 | ||
114 | return response | ||
115 | |||
97 | 116 | args = request.args | |
98 | 117 | ||
99 | 118 | # if no arguments are passed, its an invalid request | |
… | … | ||
135 | 135 | print 'recvd params' | |
136 | 136 | print params | |
137 | 137 | ||
138 | response = make_response() | ||
139 | 138 | ||
140 | 139 | sweets = Sweet.query.filter_by(**params).all() | |
141 | 140 | ||
142 | 141 | if len(sweets) == 0: | |
142 | print 'No sweets found to satisfy query..' | ||
143 | 143 | abort(404) | |
144 | 144 | ||
145 | 145 | swts = [i.to_dict() for i in sweets] | |
… | … | ||
176 | 176 | ||
177 | 177 | ||
178 | 178 | # Create a new Sweet Context | |
179 | @oauth.require_oauth('email', 'context') | ||
179 | 180 | @api.route('/contexts', methods=['POST']) | |
180 | 181 | def createContext(): | |
181 | 182 | ||
… | … | ||
213 | 213 | res = new_context.persist() | |
214 | 214 | ||
215 | 215 | response.status_code = 200 | |
216 | return response | ||
217 | |||
218 | |||
219 | # Send back logged in user data | ||
220 | @api.route('/users/me', methods=['GET', 'OPTIONS']) | ||
221 | @oauth.require_oauth('email') | ||
222 | def getCurrentUser(oauth_request): | ||
223 | response = make_response() | ||
224 | response = make_cross_origin_headers(response, | ||
225 | oauth_request.client.host_url) | ||
226 | response.status_code = 200 | ||
227 | |||
228 | if request.method == 'OPTIONS': | ||
229 | return response | ||
230 | |||
231 | response.data = json.dumps(oauth_request.user.to_dict()) | ||
216 | 232 | return response |
swtstore/classes/views/app.py
(13 / 7)
  | |||
3 | 3 | # classes/views/apps.py | |
4 | 4 | ||
5 | 5 | ||
6 | from flask import Module, jsonify, request, render_template, redirect, url_for | ||
6 | from flask import Module, jsonify, request, render_template, redirect,\ | ||
7 | url_for, flash, abort | ||
8 | |||
7 | 9 | from hashlib import md5 | |
8 | 10 | from werkzeug.security import gen_salt | |
9 | 11 | ||
10 | 12 | from swtstore.classes.models import Client | |
11 | 13 | from swtstore.classes.models.um import User | |
14 | from swtstore.classes.utils import urlnorm | ||
12 | 15 | ||
13 | 16 | ||
14 | 17 | app = Module(__name__) | |
… | … | ||
21 | 21 | def list(): | |
22 | 22 | current_user = User.getCurrentUser() | |
23 | 23 | if current_user is None: | |
24 | return redirect(url_for('index')) | ||
24 | return redirect(url_for('frontend.index')) | ||
25 | 25 | ||
26 | 26 | her_apps = Client.getClientsByCreator(current_user.id) | |
27 | 27 | print 'her_apps' | |
… | … | ||
34 | 34 | def register(): | |
35 | 35 | current_user = User.getCurrentUser() | |
36 | 36 | if current_user is None: | |
37 | return redirect(url_for('index')) | ||
37 | return redirect(url_for('frontend.index')) | ||
38 | 38 | ||
39 | 39 | user = current_user.to_dict() | |
40 | 40 | ||
… | … | ||
42 | 42 | return render_template('register_app.html', user=user) | |
43 | 43 | ||
44 | 44 | elif request.method == 'POST': | |
45 | if not request.form.get('name'): | ||
46 | abort(400) | ||
45 | req_fields = ['name', 'host_url', 'redirect_uris', 'scopes'] | ||
46 | for field in req_fields: | ||
47 | if not request.form.get(field): | ||
48 | abort(404) | ||
47 | 49 | ||
48 | 50 | new_app = Client( | |
49 | 51 | id = gen_salt(40), | |
… | … | ||
53 | 53 | name = request.form.get('name'), | |
54 | 54 | description = request.form.get('desc'), | |
55 | 55 | user_id = current_user.id, | |
56 | _redirect_uris = request.form.get('redirect_uris'), | ||
57 | _default_scopes = request.form.get('scopes'), | ||
56 | _host_url = request.form.get('host_url'), | ||
57 | _redirect_uris = urlnorm(request.form.get('redirect_uris')), | ||
58 | _default_scopes = ' '.join(request.form.get('scopes').split(',')), | ||
58 | 59 | _is_private = False | |
59 | 60 | ) | |
60 | 61 | new_app.persist() |
swtstore/classes/views/oauth.py
(44 / 0)
  | |||
1 | # -*- coding utf-8 -*- | ||
2 | # classes/views/oauth.py | ||
3 | |||
4 | from flask import Module, jsonify, request, render_template, redirect, url_for | ||
5 | import json | ||
6 | |||
7 | from swtstore.classes import oauth | ||
8 | from swtstore.classes.models.um import User | ||
9 | from swtstore.classes.models import Client | ||
10 | |||
11 | |||
12 | Oauth = Module(__name__) | ||
13 | |||
14 | @Oauth.route('/authorize', methods=['GET', 'POST']) | ||
15 | @oauth.authorize_handler | ||
16 | def authorize(*args, **kwargs): | ||
17 | current_user = User.getCurrentUser() | ||
18 | if current_user is None: | ||
19 | return render_template('oauth_login.html') | ||
20 | |||
21 | if request.method == 'GET': | ||
22 | client_id = kwargs.get('client_id') | ||
23 | client = Client.query.get(client_id) | ||
24 | print '/authorize: ' | ||
25 | print client | ||
26 | kwargs['client'] = client | ||
27 | kwargs['user'] = current_user | ||
28 | print kwargs | ||
29 | return render_template('authorize.html', **kwargs) | ||
30 | |||
31 | confirm = request.form.get('confirm', 'no') | ||
32 | print confirm | ||
33 | return confirm == 'yes' | ||
34 | |||
35 | @Oauth.route('/token', methods=['GET', 'POST']) | ||
36 | @oauth.token_handler | ||
37 | def access_token(): | ||
38 | #print request.form | ||
39 | print 'access token touched..' | ||
40 | return None | ||
41 | |||
42 | @Oauth.route('/errors') | ||
43 | def error(): | ||
44 | return jsonify(error=request.args.get('error')) |
  | |||
21 | 21 | def login(): | |
22 | 22 | ||
23 | 23 | response = make_response() | |
24 | response = make_cross_origin_headers(response) | ||
24 | #response = make_cross_origin_headers(response) | ||
25 | 25 | ||
26 | 26 | if 'assertion' not in request.form: | |
27 | 27 | response.status_code = 400 | |
… | … | ||
29 | 29 | ||
30 | 30 | print request.remote_addr | |
31 | 31 | data = {'assertion': request.form['assertion'], 'audience': | |
32 | 'http://localhost:5001'} | ||
32 | config.SWTSTORE_URL} | ||
33 | 33 | ||
34 | 34 | resp = requests.post(config.MOZ_PERSONA_VERIFIER, data=data, verify=True) | |
35 | 35 | print resp.status_code | |
… | … | ||
64 | 64 | def logout(): | |
65 | 65 | ||
66 | 66 | response = make_response() | |
67 | response = make_cross_origin_headers(response) | ||
67 | #response = make_cross_origin_headers(response) | ||
68 | 68 | ||
69 | 69 | if 'email' in session: | |
70 | 70 | print 'logging out ' |
swtstore/sample_config.py
(6 / 0)
  | |||
29 | 29 | ||
30 | 30 | # The Mozilla Persona Verifier Host. Leave it as it is. | |
31 | 31 | MOZ_PERSONA_VERIFIER = 'https://verifier.login.persona.org/verify' | |
32 | |||
33 | # The URL at which this app, swtstore, is deployed. | ||
34 | SWTSTORE_URL = 'http://demo.swtr.us' | ||
35 | |||
36 | # Bearer token expiry | ||
37 | OAUTH2_PROVIDER_TOKEN_EXPIRES_IN = 3600 |
Binary files differ
Binary files differ
  | |||
1 | {% extends "layout.html" %} | ||
2 | {% block body %} | ||
3 | <h4> Allow Access ?</h4> | ||
4 | <p class="text-muted"> | ||
5 | The following application wants to get permission to do stuff(?) on the <i>swt | ||
6 | web</i> platform on your behalf. | ||
7 | </p> | ||
8 | |||
9 | <form role="form" method="POST" action="{{ url_for('oauth.authorize') }}"> | ||
10 | <div class="form-group"> | ||
11 | <p class="form-control-static text-primary"> | ||
12 | {{ client.name }} at {{ client.host_url }} wants | ||
13 | to get permission to post data to swt store | ||
14 | </p> | ||
15 | </div> | ||
16 | <div class="form-group"> | ||
17 | <label class="control-label">Scopes</label> | ||
18 | <div class=""> | ||
19 | <p class="form-control-static">{{ scopes|join(',') }}</p> | ||
20 | </div> | ||
21 | </div> | ||
22 | <input type="hidden" name="client_id" value="{{ client.id }}"> | ||
23 | <input type="hidden" name="scope" value="{{ scopes|join(' ') }}"> | ||
24 | <input type="hidden" name="response_type" value="{{ response_type }}"> | ||
25 | {% if state %} | ||
26 | <input type="hidden" name="state" value="{{ state }}"> | ||
27 | {% endif %} | ||
28 | <button type="submit" name="confirm" value="yes" class="btn btn-primary">Allow</button> | ||
29 | <button type="submit" name="confirm" value="no" class="btn btn-default">Deny</button> | ||
30 | </form> | ||
31 | |||
32 | {% endblock %} | ||
33 | |||
34 | {% block scripts %} | ||
35 | |||
36 | <script> | ||
37 | var created = new Date("{{ user.created }}"); | ||
38 | window.onload = function() { | ||
39 | $('#user-created').html(created.toString()); | ||
40 | }; | ||
41 | </script> | ||
42 | |||
43 | {% endblock %} |
  | |||
1 | <!doctype html> | ||
2 | <body> | ||
3 | <em> Oops! Looks like you are not authorized to make this request!!</em> | ||
4 | </body> |
  | |||
10 | 10 | {% for sweet in sweets %} | |
11 | 11 | <li> | |
12 | 12 | <span class="who"> | |
13 | <a href="#"> @{{ sweet.who }} </a> | ||
13 | <a href="#"> | ||
14 | @{{ sweet.who.username }} | ||
15 | </a> | ||
14 | 16 | </span> | |
15 | 17 | <span class="what"> | |
16 | #{{ sweet.what.name }} | ||
18 | <b> #{{ sweet.what.name }} </b> | ||
17 | 19 | </span> | |
18 | 20 | <span class="where"> | |
19 | 21 | {{ sweet.where }} |
  | |||
4 | 4 | <meta charset="utf-8"> | |
5 | 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
6 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
7 | <title>SWeeT Store</title> | ||
7 | <title>SWT Store</title> | ||
8 | 8 | <link rel=stylesheet type=text/css href="{{ url_for('.static', filename='css/bootstrap.min.css') }}"> | |
9 | 9 | <link rel=stylesheet type=text/css href="{{ url_for('.static', filename='css/bootstrap-theme.min.css') }}"> | |
10 | 10 | <link rel=stylesheet type=text/css href="{{ url_for('.static', filename='css/style.css') }}"> | |
… | … | ||
52 | 52 | </small></a> | |
53 | 53 | </li> | |
54 | 54 | <li class="divider"></li> | |
55 | <li> <a href="#" id="logout">Logout</a> </li> | ||
55 | <li> <a href="#" id="logout"> Logout </a> </li> | ||
56 | 56 | </ul> | |
57 | 57 | </li> | |
58 | 58 | {% endif %} | |
… | … | ||
61 | 61 | </div> | |
62 | 62 | <div class="notif"> | |
63 | 63 | {% for message in get_flashed_messages() %} | |
64 | <div class="flash">{{ message }}</div> | ||
64 | <div class="alert alert-danger">{{ message }}</div> | ||
65 | 65 | {% endfor %} | |
66 | 66 | </div> | |
67 | 67 | <div class="content"> |
  | |||
8 | 8 | <div class="pull-right"> | |
9 | 9 | <span class="glyphicon glyphicon-trash"></span> | |
10 | 10 | </div> | |
11 | <div> {{ app.name }} </div> | ||
12 | <div> {{ app.description }} </div> | ||
11 | <div><h4> {{ app.name }} </h4></div> | ||
12 | <div><h5> {{ app.description }} </h5></div> | ||
13 | 13 | <div>APP ID: {{ app.id }} </div> | |
14 | 14 | <div> APP Secret: {{ app.client_secret }} </div> | |
15 | <div>Host URL: {{ app.host_url }} </div> | ||
16 | <div>Redirect URL: {{ app.redirect_uris|join(', ') }} </div> | ||
17 | <div>Scopes: {{ app.default_scopes|join(', ') }} </div> | ||
15 | 18 | </div> | |
16 | 19 | {% endfor %} | |
17 | 20 | </ul> |
  | |||
15 | 15 | </textarea> | |
16 | 16 | </div> | |
17 | 17 | <div class="form-group"> | |
18 | <label for="host_url">Host URL</label> | ||
19 | <p class="help-block">URL where your app is deployed</p> | ||
20 | <input type="text" class="form-control" name="host_url" id="host_url" placeholder="host URL"> | ||
21 | </div> | ||
22 | <div class="form-group"> | ||
18 | 23 | <label for="redirect_uris">Redirect URLs</label> | |
19 | 24 | <p class="help-block">Your app URL where it should be redirected once the user is authorized.</p> | |
20 | 25 | <input type="text" class="form-control" name="redirect_uris" id="redirect_uris" placeholder="redirect URLs"> | |
… | … | ||
30 | 30 | </div> | |
31 | 31 | <button type="submit" class="btn btn-primary">Register</button> | |
32 | 32 | </form> | |
33 | {% endblock %} | ||
34 | {% block scripts %} | ||
35 | <script> | ||
36 | // form validation | ||
37 | /*$('form').on('submit', function(event) { | ||
38 | console.log('here..'); | ||
39 | if(!$('#name').val()) { | ||
40 | event.preventDefault(); | ||
41 | $('#name').parent().addClass('has-feedback'); | ||
42 | $('#name').parent().addClass('has-error'); | ||
43 | return false; | ||
44 | } | ||
45 | if(!$('#host_url').val()) { | ||
46 | event.preventDefault(); | ||
47 | $('#host_url').parent().addClass('has-feedback'); | ||
48 | $('#name').parent().addClass('has-error'); | ||
49 | return false; | ||
50 | } | ||
51 | if(!$('#redirect_uris').val()) { | ||
52 | event.preventDefault(); | ||
53 | $('#redirect_uris').parent().addClass('has-feedback'); | ||
54 | $('#name').parent().addClass('has-error'); | ||
55 | return false; | ||
56 | } | ||
57 | if(!$('#scopes').val()) { | ||
58 | event.preventDefault(); | ||
59 | $('#scopes').parent().addClass('has-feedback'); | ||
60 | $('#name').parent().addClass('has-error'); | ||
61 | return false; | ||
62 | } | ||
63 | });*/ | ||
64 | </script> | ||
33 | 65 | {% endblock %} |