You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2012/10/02 23:30:28 UTC

[31/34] git commit: [#4637] ticket:176 ForgeShortUrl improvements

[#4637] ticket:176 ForgeShortUrl improvements

* add remove functionality
* separate add and update functionality
* enforce CREATE/UPDATE permission for admin controller methods


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/773e7e22
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/773e7e22
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/773e7e22

Branch: refs/heads/db/4968
Commit: 773e7e2250864bdc0886898fd20622fa320ffa36
Parents: d3f57e9
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Sep 25 17:41:41 2012 +0300
Committer: Cory Johns <jo...@geek.net>
Committed: Thu Sep 27 19:10:45 2012 +0000

----------------------------------------------------------------------
 ForgeShortUrl/forgeshorturl/main.py                |   92 ++++++++-------
 ForgeShortUrl/forgeshorturl/templates/index.html   |   78 ++++++++++++-
 .../forgeshorturl/tests/functional/test.py         |   46 ++++++-
 ForgeShortUrl/forgeshorturl/widgets/short_url.py   |    7 +
 4 files changed, 174 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/773e7e22/ForgeShortUrl/forgeshorturl/main.py
----------------------------------------------------------------------
diff --git a/ForgeShortUrl/forgeshorturl/main.py b/ForgeShortUrl/forgeshorturl/main.py
index 6fca6f3..38bd3cc 100644
--- a/ForgeShortUrl/forgeshorturl/main.py
+++ b/ForgeShortUrl/forgeshorturl/main.py
@@ -1,4 +1,5 @@
 from tg import expose, validate, redirect, flash, request
+from tg.decorators import without_trailing_slash
 from urllib import urlencode
 
 from allura.app import Application, SitemapEntry, DefaultAdminController
@@ -18,7 +19,7 @@ from formencode import validators
 from formencode.compound import All
 
 from forgeshorturl.model.shorturl import ShortUrl
-from forgeshorturl.widgets.short_url import CreateShortUrlWidget
+import forgeshorturl.widgets.short_url as suw
 
 import logging
 
@@ -30,9 +31,10 @@ class W:
     search_results = SearchResults()
     page_list = ffw.PageList()
     page_size = ffw.PageSize()
-    create_short_url_lightbox = \
-        CreateShortUrlWidget(name='create_short_url',
-                             trigger='#sidebar a.add_short_url')
+    create_short_url_lightbox = suw.CreateShortUrlWidget(
+            name='create_short_url',
+            trigger='#sidebar a.add_short_url')
+    update_short_url_lightbox = suw.UpdateShortUrlWidget()
 
 
 class ForgeShortUrlApp(Application):
@@ -115,6 +117,7 @@ class ForgeShortUrlApp(Application):
 class RootController(BaseController):
     def __init__(self):
         c.create_short_url_lightbox = W.create_short_url_lightbox
+        c.update_short_url_lightbox = W.update_short_url_lightbox
 
     def _check_security(self):
         require_access(c.app, 'read')
@@ -196,52 +199,61 @@ class ShortURLAdminController(DefaultAdminController):
     def index(self, **kw):
         redirect(c.project.url() + 'admin/tools')
 
+    @without_trailing_slash
+    @expose('json:')
+    def remove(self, shorturl):
+        require_access(self.app, 'update')
+        ShortUrl.query.remove({
+            'app_config_id': self.app.config._id,
+            'short_name': shorturl})
+        return dict(status='ok')
+
     @expose('jinja:forgeshorturl:templates/add.html')
     @validate(dict(full_url=All(validators.URL(add_http=True),
                                 validators.NotEmpty()),
                    short_url=validators.NotEmpty()))
-    def add(self, short_url="",
-            full_url="",
-            description="",
-            private="off", **kw):
-        if (request.method == 'POST'):
+    def add(self, short_url='', full_url='', description='', private='off',
+            update=False, **kw):
+        if update:
+            require_access(self.app, 'update')
+        else:
+            require_access(self.app, 'create')
+        if request.method == 'POST':
             if pylons.c.form_errors:
-                error_msg = "Error creating Short URL: "
+                error_msg = 'Error: '
                 for msg in list(pylons.c.form_errors):
-                    names = {"short_url": "Short name", "full_url": "Full URL"}
-                    error_msg += "%s - %s " % (names[msg], c.form_errors[msg])
-                    flash(error_msg, "error")
+                    names = {'short_url': 'Short url', 'full_url': 'Full URL'}
+                    error_msg += '%s: %s ' % (names[msg], c.form_errors[msg])
+                    flash(error_msg, 'error')
                 redirect(request.referer)
 
-            if (short_url != full_url):
-                shorturl = ShortUrl.query.find({
-                    'app_config_id': self.app.config._id,
-                    'short_name': short_url}).first()
-                if shorturl is None:
-                    shorturl = ShortUrl()
-                    shorturl.created = datetime.utcnow()
-                    log_msg = 'create short url %s for %s' %\
-                              (short_url,
-                               full_url)
+            shorturl = ShortUrl.query.find({
+                'app_config_id': self.app.config._id,
+                'short_name': short_url}).first()
+
+            if shorturl is not None:
+                if not update:
+                    flash('Short url %s already exists' % short_url, 'error')
+                    redirect(request.referer)
                 else:
-                    log_msg = 'update short url %s from %s to %s' %\
-                              (short_url,
-                               shorturl.full_url,
-                               full_url)
-                shorturl.full_url = full_url
-                shorturl.short_name = short_url
-                shorturl.description = description
-                shorturl.create_user = c.user._id
+                    msg = ('update short url %s from %s to %s'
+                            % (short_url, shorturl.full_url, full_url))
+                    flash("Short url updated")
+
+            else:
+                shorturl = ShortUrl()
+                shorturl.created = datetime.utcnow()
                 shorturl.app_config_id = self.app.config._id
-                if private == "on":
-                    shorturl.private = True
-                else:
-                    shorturl.private = False
-                shorturl.last_updated = datetime.utcnow()
-                M.AuditLog.log(log_msg)
+                msg = 'create short url %s for %s' % (short_url, full_url)
                 flash("Short url created")
-            else:
-                flash("Error creating Short URL: "
-                      "Short Name and Full URL must be different", "error")
+
+            shorturl.short_name = short_url
+            shorturl.full_url = full_url
+            shorturl.description = description
+            shorturl.create_user = c.user._id
+            shorturl.private = private == 'on'
+            shorturl.last_updated = datetime.utcnow()
+
+            M.AuditLog.log(msg)
             redirect(request.referer)
         return dict(app=self.app)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/773e7e22/ForgeShortUrl/forgeshorturl/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeShortUrl/forgeshorturl/templates/index.html b/ForgeShortUrl/forgeshorturl/templates/index.html
index afd9f21..0ea37bf 100644
--- a/ForgeShortUrl/forgeshorturl/templates/index.html
+++ b/ForgeShortUrl/forgeshorturl/templates/index.html
@@ -1,4 +1,34 @@
 {% extends 'forgeshorturl:templates/master.html' %}
+
+{% set can_update = c.user and h.has_access(c.app, 'update') %}
+
+{% block extra_js %}
+  {{ super() }}
+
+  {{ c.update_short_url_lightbox.display(content='''
+<div>
+<h1>Update Short URL</h1>
+<form method="post" action="" id="update-short-url-form">
+  <input type="hidden" name="update" value="update">
+  <input type="hidden" name="short_url">
+  <label class="grid-13">Short name</label>
+  <div class="grid-13"><input type="text" name="short_url_display" style="width: 250px" disabled="disabled"></div>
+  <label class="grid-13">Full URL</label>
+  <div class="grid-13"><input type="text" name="full_url" style="width: 250px"></div>
+  <label class="grid-13">Description</label>
+  <div class="grid-13"><textarea name="description" style="width: 250px; height: 100px"></textarea></div>
+  <div class="grid-13"><input type="checkbox" name="private" id="update-checkbox-private"><label for="update-checkbox-private">Private</label></div>
+  <div class="grid-13">&nbsp;</div>
+  <hr>
+  <div class="grid-13"><div class="grid-13">&nbsp;</div>
+  <input type="submit" value="Save">
+    <a href="#" class="close">Cancel</a>
+  </div>
+</form>
+</div>
+''') }}
+{% endblock %}
+
 {% block content %}
 <table>
     <thead>
@@ -10,6 +40,7 @@
         <th>Description</th>
         <th>Created</th>
         <th>Last updated</th>
+        {% if can_update %}<th></th>{% endif %}
     </tr>
     </thead>
     {% for su in short_urls %}
@@ -26,10 +57,53 @@
         <td><small>{{ su.description }}</small></td>
         <td><small>{{ lib.abbr_date(su.created) }}</small></td>
         <td><small>{{ lib.abbr_date(su.last_updated) }}</small></td>
-
+        {% if can_update %}
+        <td>
+          <small>
+            <a class="update-url" id="update-url-{{su.short_name}}" href="{{c.project.url()}}admin/{{c.app.config.options.mount_point}}/add/">
+              Update
+            </a>
+            <script>
+              $(function() {
+                var upform = $('#update-short-url-form');
+                $('#update-url-{{su.short_name}}').click(function() {
+                  upform.attr('action', this.href);
+                  upform.find('input[name="short_url"]').val('{{ su.short_name }}');
+                  upform.find('input[name="short_url_display"]').val('{{ su.short_name }}');
+                  upform.find('input[name="full_url"]').val('{{ su.full_url }}');
+                  upform.find('textarea[name="description"]').val('{{su.description|replace("\n", "\\n")|replace("\r", "\\r")}}');
+                  if ('{{ su.private }}' == 'True') {
+                    $('#update-checkbox-private').attr('checked', 'checked');
+                  } else {
+                    $('#update-checkbox-private').removeAttr('checked');
+                  }
+                  return false;
+                });
+              });
+            </script>
+            <br>
+            <a id="remove-url-{{su.short_name}}" href="{{c.project.url()}}admin/{{c.app.config.options.mount_point}}/remove">
+              Remove
+            </a>
+            <script>
+              $(function() {
+                var cval = $.cookie('_session_id');
+                $('#remove-url-{{su.short_name}}').click(function() {
+                  var row = $(this).parents('tr');
+                  var data = {_session_id: cval, shorturl: '{{ su.short_name }}'};
+                  $.post(this.href, data, function(data, status, xhr) {
+                    if (data.status == 'ok') row.remove();
+                  });
+                  return false;
+                });
+              });
+            </script>
+          </small>
+        </td>
+        {% endif %} {# can_update #}
     </tr>
     {% endfor %}
 
 </table>
 {{ c.page_list.display(limit=limit, count=count, page=pagenum) }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/773e7e22/ForgeShortUrl/forgeshorturl/tests/functional/test.py
----------------------------------------------------------------------
diff --git a/ForgeShortUrl/forgeshorturl/tests/functional/test.py b/ForgeShortUrl/forgeshorturl/tests/functional/test.py
index dc8ead1..a4c36c6 100644
--- a/ForgeShortUrl/forgeshorturl/tests/functional/test.py
+++ b/ForgeShortUrl/forgeshorturl/tests/functional/test.py
@@ -1,6 +1,11 @@
+import pylons
+pylons.c = pylons.tmpl_context
+from pylons import c
 from allura.tests import decorators as td
 from alluratest.controller import TestController
 
+from forgeshorturl.model import ShortUrl
+
 
 class TestRootController(TestController):
     def setUp(self):
@@ -18,11 +23,22 @@ class TestRootController(TestController):
         response.form.submit()
         redirected = self.app.get('/url/test').follow()
         assert redirected.request.url == 'http://www.google.com/'
+
+    def test_shorturl_update(self):
         response = self.app.get('/admin/url/add')
-        response.form['short_url'] = 'test'
-        response.form['full_url'] = 'http://www.yahoo.com/'
+        response.form['short_url'] = 'g'
+        response.form['full_url'] = 'http://www.google.com/'
         response.form.submit()
-        redirected = self.app.get('/url/test').follow()
+        redirected = self.app.get('/url/g').follow()
+        assert redirected.request.url == 'http://www.google.com/'
+
+        response = self.app.get('/url/')
+        form = response.forms['update-short-url-form']
+        form['short_url'] = 'g'
+        form['full_url'] = 'http://www.yahoo.com/'
+        form.action = '/admin/url/add/'
+        form.submit()
+        redirected = self.app.get('/url/g').follow()
         assert redirected.request.url == 'http://www.yahoo.com/'
 
     def test_shorturl_not_found(self):
@@ -50,10 +66,26 @@ class TestRootController(TestController):
                      status=302)
 
     def test_shorturl_errors(self):
-        d = dict(short_url='http://www.amazone.com/',
-                 full_url='http://www.amazone.com/')
+        d = dict(short_url='amazone',
+                 full_url='amazone')
         r = self.app.post('/admin/url/add', params=d)
         assert 'error' in self.webflash(r)
-        d = dict(short_url='http://www.amazone.com/', full_url='amazone')
+        d = dict(short_url='test', full_url='http://google.com/')
         r = self.app.post('/admin/url/add', params=d)
-        assert 'error' in self.webflash(r)
+        d['full_url'] = 'http://yahoo.com'
+        r = self.app.post('/admin/url/add', params=d)
+        assert 'exists' in self.webflash(r)
+
+    def test_shorturl_remove(self):
+        self.app.post('/admin/url/add',
+                params=dict(short_url='g', full_url='http://google.com/'))
+        assert ShortUrl.query.find(app_config_id=c.app.config._id).count() == 1
+        self.app.post('/admin/url/remove', params=dict(shorturl='g'))
+        assert ShortUrl.query.find(app_config_id=c.app.config._id).count() == 0
+
+    def test_shorturl_permissions(self):
+        self.app.post('/admin/url/add',
+                params=dict(short_url='g', full_url='http://google.com/'),
+                extra_environ=dict(username='test-user'), status=403)
+        self.app.post('/admin/url/remove', params=dict(shorturl='g'),
+                extra_environ=dict(username='test-user'), status=403)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/773e7e22/ForgeShortUrl/forgeshorturl/widgets/short_url.py
----------------------------------------------------------------------
diff --git a/ForgeShortUrl/forgeshorturl/widgets/short_url.py b/ForgeShortUrl/forgeshorturl/widgets/short_url.py
index cc040e8..50a478c 100644
--- a/ForgeShortUrl/forgeshorturl/widgets/short_url.py
+++ b/ForgeShortUrl/forgeshorturl/widgets/short_url.py
@@ -6,3 +6,10 @@ class CreateShortUrlWidget(ffw.Lightbox):
     def resources(self):
         for r in super(CreateShortUrlWidget, self).resources():
             yield r
+
+
+class UpdateShortUrlWidget(ffw.Lightbox):
+    defaults = dict(
+            ffw.Lightbox.defaults,
+            name='update-short-url-modal',
+            trigger='a.update-url')