Commit 427df6dadcb9594532cf04160a8559056cb9caee

Persist user authorization of an app

   - Add authorized_clients table, a normalized table to store authorization
     done by user for an app. Now when a user authorizes an app(grants
permission), it is remembered by swtstore and it does not ask the user to allow
the app every time.

  - Add route /users/me/authorized_apps to list all the apps authorized by
    current user, and an interface to revoke access to specific apps.

  - Structured the templates folder.
dbsetup.py
(1 / 1)
  
2020
2121# Import all modules which represents a SQLAlchemy model;
2222# they have corresponding tables that are needed to be created
23from swtstore.classes.models import Sweet, Context, Client
23from swtstore.classes.models import Sweet, Context, Client, AuthorizedClients
2424from swtstore.classes.models.um import User, Group, Membership
2525
2626# Create them!
  
1919# Run the server if this script is directly executed
2020# Presumably, this is development mode
2121if __name__ == '__main__':
22 app.run(host='0.0.0.0', port=5001)
22 app.run(debug=True, host='0.0.0.0', port=5001)
  
11from context import Context
22from sweet import Sweet
3from client import Client
3from client import Client, AuthorizedClients
  
219219@oauth.usergetter
220220def getUser():
221221 return User.getCurrentUser()
222
223
224
225# Authorized Clients
226class AuthorizedClients(db.Model):
227 """
228 The clients authorized by users
229 """
230
231 __tablename__ = 'authorized_clients'
232
233 id = db.Column(db.Integer, primary_key=True)
234
235 client_id = db.Column(db.String(40), db.ForeignKey('clients.id'),
236 nullable=False)
237 client = db.relationship('Client')
238
239 user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
240 user = db.relationship('User')
241
242 def persist(self):
243 db.session.add(self)
244 db.session.commit()
245
246 @staticmethod
247 def revoke(**kwargs):
248 user = kwargs.get('user')
249 client = kwargs.get('client')
250 authorization = AuthorizedClients.query.filter_by(user_id=user.id,
251 client_id=client.client_id).first()
252 current_app.logger.debug('authorization to be revoked-- %s',
253 authorization)
254 db.session.delete(authorization)
255 db.session.commit()
256
257 @staticmethod
258 def getByUser(user):
259 authorized_clients = [row.client for row in \
260 AuthorizedClients.query.filter_by(user_id=user.id).all()]
261
262 current_app.logger.debug('authorized clients %s', authorized_clients)
263
264 return authorized_clients
  
2222 return redirect(url_for('frontend.index'))
2323
2424 if request.method == 'GET':
25 return render_template('register_app.html')
25 return render_template('app/register.html')
2626
2727 elif request.method == 'POST':
2828 req_fields = ['name', 'host_url', 'redirect_uris', 'scopes']
  
1717 return redirect(url_for('frontend.index'))
1818
1919 if request.method == 'GET':
20 return render_template('register_context.html')
20 return render_template('context/register.html')
2121
2222 if request.method == 'POST':
2323 if not request.form.get('name') or not request.form.get('defn'):
  
1919
2020 user = User.getCurrentUser()
2121
22 return render_template('index.html', sweets=sweets)
22 return render_template('frontend/index.html', sweets=sweets)
2323
2424
2525# Create a new sweet context
  
33
44from flask import Module, jsonify, request, render_template, redirect,\
55 url_for, current_app
6import requests
67
78from swtstore.classes import oauth
89from swtstore.classes.models.um import User
9from swtstore.classes.models import Client
10from swtstore.classes.models import Client, AuthorizedClients
1011
1112
1213Oauth = Module(__name__)
1314
15
1416@Oauth.route('/authorize', methods=['GET', 'POST'])
1517@oauth.authorize_handler
1618def authorize(*args, **kwargs):
1719 current_user = User.getCurrentUser()
1820 if current_user is None:
19 return render_template('oauth_login.html')
21 return render_template('oauth/login.html')
2022
2123 if request.method == 'GET':
2224 client_id = kwargs.get('client_id')
2727 kwargs['client'] = client
2828 kwargs['user'] = current_user
2929 current_app.logger.debug('kwargs %s', kwargs)
30 return render_template('authorize.html', **kwargs)
3130
31 # See if this client is already authorized by user. If not then return
32 # a HTML to allow access.
33 authorized_clients = AuthorizedClients.getByUser(current_user)
34 if client in authorized_clients:
35 return render_template('oauth/authorized.html', **kwargs)
36 else:
37 return render_template('oauth/authorize.html', **kwargs)
38
39
3240 confirm = request.form.get('confirm', 'no')
41 authorized = request.form.get('authorized', 'no')
3342 current_app.logger.debug('confirm authorize from user: %s', confirm)
34 return confirm == 'yes'
43 client = Client.query.get(request.form.get('client_id'))
44
45 if authorized == 'yes':
46 return True
47 else:
48 if confirm == 'yes':
49 authorization = AuthorizedClients(user=current_user, client=client)
50 authorization.persist()
51 return True
52 else:
53 return False
54
3555
3656@Oauth.route('/token', methods=['GET', 'POST'])
3757@oauth.token_handler
  
2323 sweet = Sweet.query.get(id)
2424 if sweet:
2525 print "sweet found " + str(sweet)
26 return render_template('specific_sweet.html', sweet=sweet)
26 return render_template('sweet/specific.html', sweet=sweet)
2727 else:
2828 abort(404)
  
99
1010# swtstore imports
1111from swtstore.classes.models.um import User
12from swtstore.classes.models import Sweet, Context, Client
12from swtstore.classes.models import Sweet, Context, Client, AuthorizedClients
1313
1414from swtstore.classes.utils.httputils import makeCORSHeaders
1515from swtstore.config import DefaultConfig
8989 return redirect(url_for('frontend.index'))
9090
9191 if request.method == 'GET':
92 return render_template('me.html', user=current_user)
92 return render_template('user/me.html', user=current_user)
9393
94 # else POST request
9495 username = request.form.get('username')
9596
9697 current_app.logger.debug('Updating username of %s to %s',
110110 return redirect(url_for('frontend.index'))
111111
112112 swts = Sweet.getByCreator(user)
113 return render_template('my_sweets.html', sweets=swts)
113 return render_template('user/sweets.html', sweets=swts)
114114
115115
116116@user.route('/me/contexts', methods=['GET'])
121121 return redirect(url_for('frontend.index'))
122122
123123 contexts = Context.getByCreator(user.id)
124 return render_template('my_contexts.html', contexts=contexts)
124 return render_template('user/contexts.html', contexts=contexts)
125125
126126
127127@user.route('/me/apps', methods=['GET'])
133133 return redirect(url_for('frontend.index'))
134134
135135 apps = Client.getClientsByCreator(user.id)
136 return render_template('my_apps.html', apps=apps)
136 return render_template('user/apps.html', apps=apps)
137
138@user.route('/me/authorized_apps', methods=['GET', 'POST'])
139def authorizedApps():
140
141 user = User.getCurrentUser()
142 if user is None:
143 return redirect(url_for('frontend.index'))
144
145 if request.method == 'GET':
146 authorized_clients = AuthorizedClients.getByUser(user)
147 return render_template('user/authorized_apps.html',
148 authorized_clients=authorized_clients)
149
150 # else POST request
151 client_id = request.form.get('revoke-id', '')
152 if client_id:
153 client = Client.query.get(client_id)
154 current_app.logger.info('user %s revoking access to %s', user, client)
155 AuthorizedClients.revoke(user=user, client=client)
156
157 return redirect(url_for('authorizedApps'))
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if apps|length > 0 %}
5 <ul>
6 {% for app in apps %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div><h4> {{ app.name }} </h4></div>
12 <div><h5> {{ app.description }} </h5></div>
13 <div>APP ID: {{ app.id }} </div>
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>
18 </div>
19 {% endfor %}
20 </ul>
21 {% else %}
22 <em> You haven't registered any apps yet! </em>
23 {% endif %}
24</div>
25{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<h4> Register a new app with the <i>swt web</i> platform </h4>
4<p class="text-muted"> Please fill in the details below and click Register button </p>
5
6<form role="form" method="POST" action="{{ url_for('app.register') }}">
7 <div class="form-group">
8 <label for="name">Name </label>
9 <input type="text" class="form-control" name="name" id="name" placeholder="Name of the application">
10 </div>
11 <div class="form-group">
12 <label for="desc">Description</label>
13 <p class="help-block"> Brief description of your application. (Optional)</p>
14 <textarea class="form-control" rows="4" id="desc" name="desc">
15 </textarea>
16 </div>
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">
23 <label for="redirect_uris">Redirect URLs</label>
24 <p class="help-block">Your app URL where it should be redirected once the user is authorized.</p>
25 <input type="text" class="form-control" name="redirect_uris" id="redirect_uris" placeholder="redirect URLs">
26 </div>
27 <div class="form-group">
28 <label for="scopes">Scopes</label>
29 <input type="text" class="form-control" name="scopes" id="scopes" value="email">
30 </div>
31 <button type="submit" class="btn btn-primary">Register</button>
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>
65{% endblock %}
  
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{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if contexts|length > 0 %}
5 <ul>
6 {% for context in contexts %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div> {{ context.name }} </div>
12 <div> {{ context.definition }} </div>
13 </div>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <em> You haven't registered any contexts yet! </em>
18 {% endif %}
19</div>
20{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<h4> Register a new context with the <i>swt web</i> platform </h4>
4<p class="text-muted"> Please fill in the details below and click Register button </p>
5
6<form role="form" method="POST" action="{{ url_for('context.register') }}">
7 <div class="form-group">
8 <label for="name">Name </label>
9 <input type="text" class="form-control" name="name" id="name" placeholder="Name of the context">
10 </div>
11 <div class="form-group">
12 <label for="defn">Definition</label>
13 <p class="help-block"> JSON-LD definition. Insert a JSON-LD.</p>
14 <textarea class="form-control" rows="4" id="defn" name="defn">
15 </textarea>
16 </div>
17 <button type="submit" class="btn btn-primary">Register</button>
18</form>
19{% endblock %}
  
1{% extends "layout.html" %}
2
3{% block body %}
4 <div id="store-stats">
5 </div>
6
7 {% if sweets|length > 0 %}
8
9 <ul class="entries unstyled">
10 {% for sweet in sweets %}
11 <li>
12 <span class="who">
13 <a href="#">
14 @{{ sweet.who.username }}
15 </a>
16 </span>
17 <span class="what">
18 <b> #{{ sweet.what.name }} </b>
19 </span>
20 <span class="where">
21 {{ sweet.where }}
22 </span>
23 <p></p>
24 <span class="how">
25 {{ sweet.how|escape|safe }}
26 </span>
27
28 <small><i>created: {{sweet.created }}</i></small>
29
30 <span class="pull-right permalink">
31 <a href="{{ url_for('sweet.showSweet', id=sweet.id) }}">
32 <i class="glyphicon glyphicon-share"></i>
33 </a>
34 </li>
35 {% endfor %}
36 </ul>
37
38 {% else %}
39 <div class="row">
40 <div class="col-md-5">
41 <h4><em>Unbelievable! No sweets yet!!</em></h4>
42 </div>
43 </div>
44 {% endif %}
45
46{% endblock %}
  
1{% extends "layout.html" %}
2
3{% block body %}
4 <div id="store-stats">
5 </div>
6
7 {% if sweets|length > 0 %}
8
9 <ul class="entries unstyled">
10 {% for sweet in sweets %}
11 <li>
12 <span class="who">
13 <a href="#">
14 @{{ sweet.who.username }}
15 </a>
16 </span>
17 <span class="what">
18 <b> #{{ sweet.what.name }} </b>
19 </span>
20 <span class="where">
21 {{ sweet.where }}
22 </span>
23 <p></p>
24 <span class="how">
25 {{ sweet.how|escape|safe }}
26 </span>
27
28 <small><i>created: {{sweet.created }}</i></small>
29
30 <span class="pull-right permalink">
31 <a href="{{ url_for('sweet.showSweet', id=sweet.id) }}">
32 <i class="glyphicon glyphicon-share"></i>
33 </a>
34 </li>
35 {% endfor %}
36 </ul>
37
38 {% else %}
39 <div class="row">
40 <div class="col-md-5">
41 <h4><em>Unbelievable! No sweets yet!!</em></h4>
42 </div>
43 </div>
44 {% endif %}
45
46{% endblock %}
  
5151 {{ session.email }}
5252 </small></a>
5353 </li>
54 <li>
55 <a href="{{ url_for('user.authorizedApps') }}">
56 My authorized apps
57 </a>
58 </li>
5459 <li class="divider"></li>
5560 <li> <a href="#" id="logout"> Logout </a> </li>
5661 </ul>
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if apps|length > 0 %}
5 <ul>
6 {% for app in apps %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div><h4> {{ app.name }} </h4></div>
12 <div><h5> {{ app.description }} </h5></div>
13 <div>APP ID: {{ app.id }} </div>
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>
18 </div>
19 {% endfor %}
20 </ul>
21 {% else %}
22 <em> You haven't registered any apps yet! </em>
23 {% endif %}
24</div>
25{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if contexts|length > 0 %}
5 <ul>
6 {% for context in contexts %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div> {{ context.name }} </div>
12 <div> {{ context.definition }} </div>
13 </div>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <em> You haven't registered any contexts yet! </em>
18 {% endif %}
19</div>
20{% endblock %}
  
1
2{% extends "layout.html" %}
3{% block body %}
4
5<h4> Update your profile details </h4>
6
7<p class="text-muted"> Please fill in the details below and click update button </p>
8
9<form role="form" method="POST" action="{{ url_for('user.profile') }}">
10 <div class="form-group">
11 <label for="username">Username</label>
12 <input type="text" class="form-control" name="username" id="username"
13 placeholder="Username you are going to use" value="{{ user.username}}">
14 </div>
15 <div class="form-group">
16 <label class="control-label">Email</label>
17 <div class="">
18 <p class="form-control-static">{{ user.email }}</p>
19 </div>
20 </div>
21 <div class="form-group">
22 <label class="control-label">Account created </label>
23 <div class="">
24 <p class="form-control-static" id="user-created">
25 {{ user.created }}
26 </p>
27 </div>
28 </div>
29 <button type="submit" class="btn btn-primary">Update</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{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if apps|length > 0 %}
5 <ul>
6 {% for app in apps %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div><h4> {{ app.name }} </h4></div>
12 <div><h5> {{ app.description }} </h5></div>
13 <div>APP ID: {{ app.id }} </div>
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>
18 </div>
19 {% endfor %}
20 </ul>
21 {% else %}
22 <em> You haven't registered any apps yet! </em>
23 {% endif %}
24</div>
25{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if contexts|length > 0 %}
5 <ul>
6 {% for context in contexts %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div> {{ context.name }} </div>
12 <div> {{ context.definition }} </div>
13 </div>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <em> You haven't registered any contexts yet! </em>
18 {% endif %}
19</div>
20{% endblock %}
  
1{% extends "layout.html" %}
2
3{% block body %}
4
5 {% if sweets|length > 0 %}
6
7 <ul class="entries unstyled">
8 {% for sweet in sweets %}
9 <li>
10 <span class="who">
11 <a href="#">
12 @{{ sweet.who.username }}
13 </a>
14 </span>
15 <span class="what">
16 <b> #{{ sweet.what.name }} </b>
17 </span>
18 <span class="where">
19 {{ sweet.where }}
20 </span>
21 <p></p>
22 <span class="how">
23 {{ sweet.how|tojson }}
24 </span>
25
26 <small><i>created: {{sweet.created }}</i></small>
27
28 <span class="pull-right permalink">
29 <a href="#">
30 <i class="glyphicon glyphicon-share"></i>
31 </a>
32 </span>
33 <span class="pull-right edit-sweet" for="{{ sweet.id }}">
34 <a href="#">
35 <i class="glyphicon glyphicon-edit"></i>
36 </a>
37 </span>
38 </li>
39 {% endfor %}
40 </ul>
41
42 {% else %}
43 <div class="row">
44 <div class="col-md-5">
45 <h4><em>Unbelievable! No sweets yet!!</em></h4>
46 </div>
47 </div>
48 {% endif %}
49
50 <div class="modal fade" id="edit-sweet-modal">
51 <div class="modal-dialog">
52 <div class="modal-content">
53 <div class="modal-header">
54 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
55 <h4 class="modal-title">Edit Sweet </h4>
56 </div>
57 <div class="modal-body"></div>
58 <div
59 class="modal-footer">
60 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
61 <button type="button" class="btn btn-primary" id="save-edited-sweet">Save changes</button>
62 </div>
63 </div><!-- /.modal-content -->
64 </div><!-- /.modal-dialog -->
65 </div><!-- /.modal -->
66
67{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<h4> Register a new app with the <i>swt web</i> platform </h4>
4<p class="text-muted"> Please fill in the details below and click Register button </p>
5
6<form role="form" method="POST" action="{{ url_for('app.register') }}">
7 <div class="form-group">
8 <label for="name">Name </label>
9 <input type="text" class="form-control" name="name" id="name" placeholder="Name of the application">
10 </div>
11 <div class="form-group">
12 <label for="desc">Description</label>
13 <p class="help-block"> Brief description of your application. (Optional)</p>
14 <textarea class="form-control" rows="4" id="desc" name="desc">
15 </textarea>
16 </div>
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">
23 <label for="redirect_uris">Redirect URLs</label>
24 <p class="help-block">Your app URL where it should be redirected once the user is authorized.</p>
25 <input type="text" class="form-control" name="redirect_uris" id="redirect_uris" placeholder="redirect URLs">
26 </div>
27 <div class="form-group">
28 <label for="scopes">Scopes</label>
29 <input type="text" class="form-control" name="scopes" id="scopes" value="email">
30 </div>
31 <button type="submit" class="btn btn-primary">Register</button>
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>
65{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<h4> Register a new context with the <i>swt web</i> platform </h4>
4<p class="text-muted"> Please fill in the details below and click Register button </p>
5
6<form role="form" method="POST" action="{{ url_for('context.register') }}">
7 <div class="form-group">
8 <label for="name">Name </label>
9 <input type="text" class="form-control" name="name" id="name" placeholder="Name of the context">
10 </div>
11 <div class="form-group">
12 <label for="defn">Definition</label>
13 <p class="help-block"> JSON-LD definition. Insert a JSON-LD.</p>
14 <textarea class="form-control" rows="4" id="defn" name="defn">
15 </textarea>
16 </div>
17 <button type="submit" class="btn btn-primary">Register</button>
18</form>
19{% endblock %}
  
1{% extends "layout.html" %}
2
3{% block body %}
4
5<ul class="entries unstyled">
6 <li>
7 <span class="who">
8 <a href="#">
9 @{{ sweet.who.username }}
10 </a>
11 </span>
12 <span class="what">
13 <b> #{{ sweet.what.name }} </b>
14 </span>
15 <span class="where">
16 {{ sweet.where }}
17 </span>
18 <p></p>
19 <span class="how">
20 {{ sweet.how|escape|safe }}
21 </span>
22
23 <small><i>created: {{sweet.created }}</i></small>
24 </li>
25</ul>
26
27{% endblock %}
  
1{% extends "layout.html" %}
2
3{% block body %}
4
5<ul class="entries unstyled">
6 <li>
7 <span class="who">
8 <a href="#">
9 @{{ sweet.who.username }}
10 </a>
11 </span>
12 <span class="what">
13 <b> #{{ sweet.what.name }} </b>
14 </span>
15 <span class="where">
16 {{ sweet.where }}
17 </span>
18 <p></p>
19 <span class="how">
20 {{ sweet.how|escape|safe }}
21 </span>
22
23 <small><i>created: {{sweet.created }}</i></small>
24 </li>
25</ul>
26
27{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if apps|length > 0 %}
5 <ul>
6 {% for app in apps %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div><h4> {{ app.name }} </h4></div>
12 <div><h5> {{ app.description }} </h5></div>
13 <div>APP ID: {{ app.id }} </div>
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>
18 </div>
19 {% endfor %}
20 </ul>
21 {% else %}
22 <em> You haven't registered any apps yet! </em>
23 {% endif %}
24</div>
25{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3
4{% if authorized_clients | length > 0 %}
5<h4> Your authorized apps </h4>
6
7<p class="text-muted">
8 You have given access to these apps to post sweets
9 to the swtstore on your behalf. You can revoke access to specific apps.
10</p>
11
12<form role="form" method="POST" action="{{ url_for('user.authorizedApps') }}">
13 <div class="form-group">
14 <ul>
15 {% for client in authorized_clients %}
16 <li class="authorized_apps">
17 <p class="form-control-static">
18 <b>{{ client.name }}</b>: {{ client.description }}
19 <button type="submit" name="revoke-id" value="{{ client.client_id }}"
20 class="btn btn-sm btn-primary pull-right">Revoke Access</button>
21 </p>
22 </li>
23 {% endfor %}
24 </ul>
25 </div>
26</form>
27{% else %}
28<i> You have not authorized any apps to access swtstore yet.</i>
29{% endif %}
30
31{% endblock %}
32
33{% block scripts %}
34
35<script>
36</script>
37
38{% endblock %}
  
1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if contexts|length > 0 %}
5 <ul>
6 {% for context in contexts %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div> {{ context.name }} </div>
12 <div> {{ context.definition }} </div>
13 </div>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <em> You haven't registered any contexts yet! </em>
18 {% endif %}
19</div>
20{% endblock %}
  
1
2{% extends "layout.html" %}
3{% block body %}
4
5<h4> Update your profile details </h4>
6
7<p class="text-muted"> Please fill in the details below and click update button </p>
8
9<form role="form" method="POST" action="{{ url_for('user.profile') }}">
10 <div class="form-group">
11 <label for="username">Username</label>
12 <input type="text" class="form-control" name="username" id="username"
13 placeholder="Username you are going to use" value="{{ user.username}}">
14 </div>
15 <div class="form-group">
16 <label class="control-label">Email</label>
17 <div class="">
18 <p class="form-control-static">{{ user.email }}</p>
19 </div>
20 </div>
21 <div class="form-group">
22 <label class="control-label">Account created </label>
23 <div class="">
24 <p class="form-control-static" id="user-created">
25 {{ user.created }}
26 </p>
27 </div>
28 </div>
29 <button type="submit" class="btn btn-primary">Update</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{% extends "layout.html" %}
2
3{% block body %}
4
5 {% if sweets|length > 0 %}
6
7 <ul class="entries unstyled">
8 {% for sweet in sweets %}
9 <li>
10 <span class="who">
11 <a href="#">
12 @{{ sweet.who.username }}
13 </a>
14 </span>
15 <span class="what">
16 <b> #{{ sweet.what.name }} </b>
17 </span>
18 <span class="where">
19 {{ sweet.where }}
20 </span>
21 <p></p>
22 <span class="how">
23 {{ sweet.how|tojson }}
24 </span>
25
26 <small><i>created: {{sweet.created }}</i></small>
27
28 <span class="pull-right permalink">
29 <a href="#">
30 <i class="glyphicon glyphicon-share"></i>
31 </a>
32 </span>
33 <span class="pull-right edit-sweet" for="{{ sweet.id }}">
34 <a href="#">
35 <i class="glyphicon glyphicon-edit"></i>
36 </a>
37 </span>
38 </li>
39 {% endfor %}
40 </ul>
41
42 {% else %}
43 <div class="row">
44 <div class="col-md-5">
45 <h4><em>Unbelievable! No sweets yet!!</em></h4>
46 </div>
47 </div>
48 {% endif %}
49
50 <div class="modal fade" id="edit-sweet-modal">
51 <div class="modal-dialog">
52 <div class="modal-content">
53 <div class="modal-header">
54 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
55 <h4 class="modal-title">Edit Sweet </h4>
56 </div>
57 <div class="modal-body"></div>
58 <div
59 class="modal-footer">
60 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
61 <button type="button" class="btn btn-primary" id="save-edited-sweet">Save changes</button>
62 </div>
63 </div><!-- /.modal-content -->
64 </div><!-- /.modal-dialog -->
65 </div><!-- /.modal -->
66
67{% endblock %}