Skip to content

Commit

Permalink
Enable the ability to delete an example.
Browse files Browse the repository at this point in the history
Add additional columns (timestamp, added_by) to example list table.
Don't explicitly define 'example_id' as a property, as App Engine gives us an id automatically.
  • Loading branch information
kamalgill committed May 13, 2012
1 parent 576284f commit f767d6b
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/application/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@


class ExampleForm(wtf.Form):
example_id = wtf.TextField('Example ID', validators=[validators.Required()])
example_title = wtf.TextField('Example Title', validators=[validators.Required()])
example_name = wtf.TextField('Name', validators=[validators.Required()])
example_description = wtf.TextAreaField('Description', validators=[validators.Required()])
4 changes: 2 additions & 2 deletions src/application/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class ExampleModel(db.Model):
"""Example Model"""
example_id = db.StringProperty(required=True)
example_title = db.StringProperty(required=True)
example_name = db.StringProperty(required=True)
example_description = db.TextProperty(required=True)
added_by = db.UserProperty()
timestamp = db.DateTimeProperty(auto_now_add=True)
35 changes: 24 additions & 11 deletions src/application/templates/list_examples.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{% block style_block %}
<style type="text/css">
table.table { width: 50%; }
table.table { width: 60%; }
</style>
{% endblock %}

Expand All @@ -14,17 +14,30 @@ <h1 id="">All Examples</h1>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Name</th>
<th>Description</th>
<th>Added by</th>
<th>Added on</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for example in examples %}
{% set example_id = example.key().id() %}
<tr>
<td>{{ example.example_id }}</td>
<td>{{ example.example_title }}</td>
<td>{{ example_id }}</td>
<td>{{ example.example_name }}</td>
<td>{{ example.example_description }}</td>
<td>{{ example.added_by }}</td>
<td>{{ example.timestamp.strftime('%b %d, %Y %I:%M %p') }}</td>
<td>
<form method="post" action="{{ url_for('delete_example', example_id=example_id) }}">
<button class="btn">Delete</button>
</form>
</td>
</tr>
{% else %}
<tr><td colspan="2">No examples yet</td></tr>
<tr><td colspan="6">No examples yet</td></tr>
{% endfor %}
</tbody>
</table>
Expand All @@ -44,15 +57,15 @@ <h1 id="">All Examples</h1>
var FormHelpers = {
validate: function (form, evt) {
// Form validation for modal dialog
var example_id = form.find('#example_id').val();
var example_title = form.find('#example_title').val();
if (!(example_id)) {
var example_name = form.find('#example_name').val();
var example_description = form.find('#example_description').val();
if (!(example_name)) {
evt.preventDefault();
Utils.renderFieldErrorTooltip('#example_id', 'ID is required', 'right');
Utils.renderFieldErrorTooltip('#example_name', 'Name is required', 'right');
}
if (!(example_title)) {
if (!(example_description)) {
evt.preventDefault();
Utils.renderFieldErrorTooltip('#example_title', 'Title is required', 'right');
Utils.renderFieldErrorTooltip('#example_description', 'Description is required', 'right');
}
},
init: function () {
Expand Down
16 changes: 8 additions & 8 deletions src/application/templates/new_example.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ <h3>Add a New Example</h3>
<fieldset>
{{ form.hidden_tag() }}
<div class="control-group">
<div class="control-label">{{ form.example_id.label }}</div>
<div class="control-label">{{ form.example_name.label }}</div>
<div class="controls">
{{ form.example_id|safe }}
{% if form.example_id.errors %}
{{ form.example_name|safe }}
{% if form.example_name.errors %}
<ul class="errors">
{% for error in form.example_id.errors %}
{% for error in form.example_name.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
<div class="control-group">
<div class="control-label">{{ form.example_title.label }}</div>
<div class="control-label">{{ form.example_description.label }}</div>
<div class="controls">
{{ form.example_title|safe }}
{% if form.example_title.errors %}
{{ form.example_description|safe }}
{% if form.example_description.errors %}
<ul class="errors">
{% for error in form.example_title.errors %}
{% for error in form.example_description.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
Expand Down
2 changes: 2 additions & 0 deletions src/application/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
# Contrived admin-only view example
app.add_url_rule('/admin_only', 'admin_only', view_func=views.admin_only)

# Delete an example (post method only)
app.add_url_rule('/examples/delete/<example_id>', view_func=views.delete_example, methods=['POST'])


## Error handlers
Expand Down
21 changes: 18 additions & 3 deletions src/application/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,35 @@ def list_examples():
form = ExampleForm()
if form.validate_on_submit():
example = ExampleModel(
example_id = form.example_id.data,
example_title = form.example_title.data,
example_name = form.example_name.data,
example_description = form.example_description.data,
added_by = users.get_current_user()
)
try:
example.put()
flash(u'Example successfully saved.', 'success')
example_id = example.key().id()
flash(u'Example %s successfully saved.' % example_id, 'success')
return redirect(url_for('list_examples'))
except CapabilityDisabledError:
flash(u'App Engine Datastore is currently in read-only mode.', 'info')
return redirect(url_for('list_examples'))
return render_template('list_examples.html', examples=examples, form=form)


@login_required
def delete_example(example_id):
"""Delete an example object"""
int_example_id = int(example_id)
example = ExampleModel.get_by_id(int_example_id)
try:
example.delete()
flash(u'Example %s successfully deleted.' % example_id, 'success')
return redirect(url_for('list_examples'))
except CapabilityDisabledError:
flash(u'App Engine Datastore is currently in read-only mode.', 'info')
return redirect(url_for('list_examples'))


@admin_required
def admin_only():
"""This view requires an admin account"""
Expand Down
19 changes: 9 additions & 10 deletions src/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
"""
tests.py
TODO: These tests need to be updated to support the Python 2.7 runtime
"""
import os
import unittest

from google.appengine.ext import testbed

import main
from application import models
from application import app


class DemoTestCase(unittest.TestCase):
def setUp(self):
# Flask apps testing. See: http://flask.pocoo.org/docs/testing/
main.app.config['TESTING'] = True
main.app.config['CSRF_ENABLED'] = False
self.app = main.app.test_client()
app.config['TESTING'] = True
app.config['CSRF_ENABLED'] = False
self.app = app.test_client()
# Setups app engine test bed. See: http://code.google.com/appengine/docs/python/tools/localunittesting.html#Introducing_the_Python_Testing_Utilities
self.testbed = testbed.Testbed()
self.testbed.activate()
Expand All @@ -33,9 +35,6 @@ def setCurrentUser(self, email, user_id, is_admin=False):
os.environ['USER_ID'] = user_id or ''
os.environ['USER_IS_ADMIN'] = '1' if is_admin else '0'

def logoutCurrentUser():
setCurrentUser(None, None)

def test_home_redirects(self):
rv = self.app.get('/')
assert rv.status == '302 FOUND'
Expand All @@ -51,8 +50,8 @@ def test_displays_no_data(self):
def test_inserts_data(self):
self.setCurrentUser(u'john@example.com', u'123')
rv = self.app.post('/example/new', data=dict(
example_id='42',
example_title='An example'
example_name='An example',
example_description='Description of an example'
), follow_redirects=True)
assert 'Example successfully saved' in rv.data

Expand Down

0 comments on commit f767d6b

Please sign in to comment.