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 2016/01/08 19:02:32 UTC

[02/10] allura git commit: [#8024] ticket:872 Add, edit, remove for site notifications

[#8024] ticket:872 Add, edit, remove for site notifications

* Add controller for Adding, editing and deleting SiteNotifications,
* Add templates for this cntrollers
* Edit link in site_admin_site_notifications_list
* Add tests


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

Branch: refs/heads/master
Commit: 454565e69a2fd5d6529e925289c9350caade5d05
Parents: ea39da6
Author: Denis Kotov <de...@gmail.com>
Authored: Fri Dec 11 14:43:51 2015 +0200
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Fri Jan 8 12:18:11 2016 -0500

----------------------------------------------------------------------
 Allura/allura/controllers/site_admin.py         |  73 ++++++++++++
 Allura/allura/lib/validators.py                 |   9 ++
 .../site_admin_site_notifications_edit.html     | 118 +++++++++++++++++++
 .../site_admin_site_notifications_list.html     |   6 +-
 .../site_admin_site_notifications_new.html      | 118 +++++++++++++++++++
 .../allura/tests/functional/test_site_admin.py  | 115 ++++++++++++++++++
 6 files changed, 436 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index ca45c46..878e9aa 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -30,6 +30,7 @@ from pylons import tmpl_context as c
 from pylons import request
 from formencode import validators, Invalid
 from webob.exc import HTTPNotFound, HTTPFound
+from ming.odm import ThreadLocalORMSession
 
 from allura.app import SitemapEntry
 from allura.lib import helpers as h
@@ -422,6 +423,14 @@ class DeleteProjectsController(object):
 
 class SiteNotificationController(object):
 
+    def __init__(self, note=None):
+        self.note = note
+
+    @expose()
+    def _lookup(self, id, *remainder):
+        note = M.notification.SiteNotification.query.get(_id=bson.ObjectId(id))
+        return SiteNotificationController(note=note), remainder
+
     def _check_security(self):
         with h.push_context(config.get('site_admin_project', 'allura'),
                             neighborhood=config.get('site_admin_project_nbhd', 'Projects')):
@@ -446,6 +455,63 @@ class SiteNotificationController(object):
             'limit': limit
         }
 
+    @expose('jinja:allura:templates/site_admin_site_notifications_new.html')
+    @without_trailing_slash
+    def new(self, **kw):
+        """Render the New SiteNotification form"""
+        return dict(
+            form_errors=c.form_errors or {},
+            form_values=c.form_values or {},
+        )
+
+    @expose()
+    @require_post()
+    @validate(v.CreateSiteNotificationSchema(), error_handler=new)
+    def create(self, active, impressions, content, user_role, page_regex, page_tool_type):
+        """Post a new note"""
+        M.notification.SiteNotification(
+            active=active, impressions=impressions, content=content,
+            user_role=user_role, page_regex=page_regex,
+            page_tool_type=page_tool_type)
+        ThreadLocalORMSession().flush_all()
+        redirect('../site_notifications')
+
+    @expose('jinja:allura:templates/site_admin_site_notifications_edit.html')
+    def edit(self):
+        if c.form_values:
+            return dict(
+                form_errors=c.form_errors or {},
+                form_values=c.form_values or {},
+            )
+        form_value = {}
+        form_value['active'] = str(self.note.active)
+        form_value['imressions'] = self.note.impressions
+        form_value['content'] = self.note.content
+        form_value['user_role'] = self.note.user_role if self.note.user_role is not None else ''
+        form_value['page_regex'] = self.note.page_regex if self.note.page_regex is not None else ''
+        form_value['page_tool_type'] = self.note.page_tool_type if self.note.page_tool_type is not None else ''
+        return dict(form_errors={},
+                    form_values=form_value)
+
+    @expose()
+    @require_post()
+    @validate(v.CreateSiteNotificationSchema(), error_handler=edit)
+    def update(self, active=True, impressions=0, content='', user_role=None, page_regex=None, page_tool_type=None):
+        self.note.active = active
+        self.note.impressions = impressions
+        self.note.content = content
+        self.note.user_role = user_role
+        self.note.page_regex = page_regex
+        self.note.page_tool_type = page_tool_type
+        ThreadLocalORMSession().flush_all()
+        redirect('..')
+
+    @expose()
+    def delete(self):
+        self.note.delete()
+        ThreadLocalORMSession().flush_all()
+        redirect(request.referer)
+
 
 class TaskManagerController(object):
 
@@ -692,3 +758,10 @@ class StatsSiteAdminExtension(SiteAdminExtension):
     def update_sidebar_menu(self, links):
         links.append(SitemapEntry('Stats', '/nf/admin/stats',
             ui_icon=g.icons['stats']))
+
+
+class SNEditC(object):
+    @expose()
+    @with_trailing_slash
+    def _default(self, *args, **kwargs):
+        redirect('/')

http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/lib/validators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 344af39..1f2bf6a 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -306,6 +306,15 @@ class CreateTaskSchema(fe.Schema):
     path = PathValidator(strip=True, if_missing={}, if_empty={})
 
 
+class CreateSiteNotificationSchema(fe.Schema):
+    active = fev.StringBool()
+    impressions = fev.Int(not_empty=True)
+    content = fev.NotEmpty(messages=dict(empty='Please enter a value'))
+    user_role = fev.FancyValidator(not_empty=False, if_empty=None)
+    page_regex = fev.FancyValidator(not_empty=False, if_empty=None)
+    page_tool_type = fev.FancyValidator(not_empty=False, if_empty=None)
+
+
 class DateValidator(fev.FancyValidator):
 
     def _to_python(self, value, state):

http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/templates/site_admin_site_notifications_edit.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_site_notifications_edit.html b/Allura/allura/templates/site_admin_site_notifications_edit.html
new file mode 100644
index 0000000..07dc916
--- /dev/null
+++ b/Allura/allura/templates/site_admin_site_notifications_edit.html
@@ -0,0 +1,118 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+{% set page="task_manager" %}
+{% set sidebar_rel = '../' %}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block extra_css %}
+<style>
+  form {
+    margin: 1em;
+  }
+  form > div {
+    margin-bottom: 1em;
+  }
+  form > div > *{
+    display: inline-block;
+    vertical-align: top;
+  }
+  form > div input,
+  form > div textarea,
+  form > div select,
+  form > .input {
+    display: block;
+    width: 300px;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    box-sizing: border-box;
+  }
+  form > div label {
+    width: 100px;
+  }
+  .error {
+    width: 300px;
+    background: none;
+    border: none;
+    color: #f00;
+    margin: 0;
+    padding: 0 0 0 .8em;
+  }
+</style>
+{% endblock %}
+
+{% macro error(field) %}
+  {% if form_errors.get(field) %}
+  <span class="error">{{form_errors.get(field)}}</span>
+  {% endif %}
+{% endmacro %}
+
+{% block content %}
+<h2>Edit Site Notification</h2>
+<form method="POST" action="update" id="editnote">
+  <div>
+    <label>Active</label>
+    <div class="input">
+      <select name="active">
+        <option value="False">No</option>
+        <option value="True" {%- if form_values.get('active') == 'True' -%}selected{%- endif -%}>Yes</option>
+      </select>
+    </div>
+    {{error('active')}}
+  </div>
+  <div>
+    <label>Impressions</label>
+    <div class="input">
+      <input name="impressions" value="{{form_values.get('impressions', '0')}}" />
+    </div>
+    {{error('impressions')}}
+  </div>
+  <div>
+    <label>Content</label>
+    <div class="input">
+      <textarea name="content" rows="4">{{form_values.get('content', '')}}</textarea>
+    </div>
+    {{error('content')}}
+  </div>
+  <div>
+    <label>User Role</label>
+    <div class="input">
+      <input name="user_role" value="{{form_values.get('user_role', '')}}" />
+    </div>
+    {{error('user_role')}}
+  </div>
+  <div>
+    <label>Page Regex</label>
+    <div class="input">
+      <input name="page_regex" value="{{form_values.get('page_regex', '')}}" />
+    </div>
+    {{error('page_regex')}}
+  </div>
+  <div>
+    <label>Page Type</label>
+    <div class="input">
+      <input name="page_tool_type" value="{{form_values.get('page_tool_type', '')}}" />
+    </div>
+    {{error('page_tool_type')}}
+  </div>
+
+
+  <input type="submit" value="Save"/><br/>
+  {{lib.csrf_token()}}
+</form>
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/templates/site_admin_site_notifications_list.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_site_notifications_list.html b/Allura/allura/templates/site_admin_site_notifications_list.html
index 7f88e54..f400a96 100644
--- a/Allura/allura/templates/site_admin_site_notifications_list.html
+++ b/Allura/allura/templates/site_admin_site_notifications_list.html
@@ -22,7 +22,7 @@
 {% extends 'allura:templates/site_admin.html' %}
 {% block content %}
   <div class="grid-23"><a href="/nf/admin">Back to Site Admin Home</a></div>
-  <div class="grid-23"><a href="">Create a new notification</a></div>
+  <div class="grid-23"><a href="new">Create a new notification</a></div>
   {{c.page_size.display(limit=limit, page=page_url, count=count)}}
   <table id="site_notifications">
     <thead>
@@ -45,8 +45,8 @@
       <td><small class="tooltip" title="{{ note.page_regex }}">{{ note.page_regex|truncate(20) if note.page_regex}}</small></td>
       <td><small>{{ note.page_tool_type if note.page_tool_type}}</small></td>
       <td>
-          <a href="">Edit</a><br>
-          <a href="">Delete</a>
+          <a href="{{ note._id }}/edit">Edit</a><br>
+          <a href="{{ note._id }}/delete">Delete</a>
       </td>
     </tr>
     {% endfor %}

http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/templates/site_admin_site_notifications_new.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_site_notifications_new.html b/Allura/allura/templates/site_admin_site_notifications_new.html
new file mode 100644
index 0000000..8123d97
--- /dev/null
+++ b/Allura/allura/templates/site_admin_site_notifications_new.html
@@ -0,0 +1,118 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+{% set page="task_manager" %}
+{% set sidebar_rel = '../' %}
+{% extends 'allura:templates/site_admin.html' %}
+
+{% block extra_css %}
+<style>
+  form {
+    margin: 1em;
+  }
+  form > div {
+    margin-bottom: 1em;
+  }
+  form > div > *{
+    display: inline-block;
+    vertical-align: top;
+  }
+  form > div input,
+  form > div textarea,
+  form > div select,
+  form > .input {
+    display: block;
+    width: 300px;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    box-sizing: border-box;
+  }
+  form > div label {
+    width: 100px;
+  }
+  .error {
+    width: 300px;
+    background: none;
+    border: none;
+    color: #f00;
+    margin: 0;
+    padding: 0 0 0 .8em;
+  }
+</style>
+{% endblock %}
+
+{% macro error(field) %}
+  {% if form_errors.get(field) %}
+  <span class="error">{{form_errors.get(field)}}</span>
+  {% endif %}
+{% endmacro %}
+
+{% block content %}
+<h2>New Site Notification</h2>
+<form method="POST" action="create" id="newnote">
+  <div>
+    <label>Active</label>
+    <div class="input">
+      <select name="active">
+        <option value="False">No</option>
+        <option value="True" {%- if form_values.get('active') == 'True' -%}selected{%- endif -%}>Yes</option>
+      </select>
+    </div>
+    {{error('active')}}
+  </div>
+  <div>
+    <label>Impressions</label>
+    <div class="input">
+      <input name="impressions" value="{{form_values.get('impressions', '0')}}" />
+    </div>
+    {{error('impressions')}}
+  </div>
+  <div>
+    <label>Content</label>
+    <div class="input">
+      <textarea name="content" rows="4">{{form_values.get('content', '')}}</textarea>
+    </div>
+    {{error('content')}}
+  </div>
+  <div>
+    <label>User Role</label>
+    <div class="input">
+      <input name="user_role" value="{{form_values.get('user_role', '')}}" />
+    </div>
+    {{error('user_role')}}
+  </div>
+  <div>
+    <label>Page Regex</label>
+    <div class="input">
+      <input name="page_regex" value="{{form_values.get('page_regex', '')}}" />
+    </div>
+    {{error('page_regex')}}
+  </div>
+  <div>
+    <label>Page Type</label>
+    <div class="input">
+      <input name="page_tool_type" value="{{form_values.get('page_tool_type', '')}}" />
+    </div>
+    {{error('page_tool_type')}}
+  </div>
+
+
+  <input type="submit" value="Save"/><br/>
+  {{lib.csrf_token()}}
+</form>
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/allura/blob/454565e6/Allura/allura/tests/functional/test_site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index 6b4187f..c8f98cc 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -18,6 +18,7 @@
 
 import json
 import datetime as dt
+import bson
 
 from mock import patch, MagicMock
 from nose.tools import assert_equal, assert_in, assert_not_in
@@ -206,6 +207,120 @@ class TestSiteAdmin(TestController):
         assert row[4].contents[0].contents[0] == 'test3'
         assert row[5].contents[0].contents[0] == 'test4'
 
+    def test_site_notification_new_template(self):
+        r = self.app.get('/nf/admin/site_notifications/new')
+
+        assert r
+        assert 'New Site Notification' in r
+        assert 'Active' in r
+        assert 'Impressions' in r
+        assert 'Content' in r
+        assert 'User Role' in r
+        assert 'Page Regex' in r
+        assert 'Page Type' in r
+
+    def test_site_notification_create(self):
+        count = M.notification.SiteNotification.query.find().count()
+        active = 'True'
+        impressions = '7'
+        content = 'test1'
+        user_role = 'test2'
+        page_regex = 'test3'
+        page_tool_type = 'test4'
+        r = self.app.post('/nf/admin/site_notifications/create', params=dict(
+            active=active,
+            impressions=impressions,
+            content=content,
+            user_role=user_role,
+            page_regex=page_regex,
+            page_tool_type=page_tool_type))
+        note = M.notification.SiteNotification.query.find().sort('_id', -1).next()
+
+        assert '/nf/admin/site_notifications' in r.location
+
+        assert M.notification.SiteNotification.query.find().count() == count + 1
+
+        assert note.active == bool('True')
+        assert note.impressions == int(impressions)
+        assert note.content == content
+        assert note.user_role == user_role
+        assert note.page_regex == page_regex
+        assert note.page_tool_type == page_tool_type
+
+    def test_site_notification_edit_template(self):
+        note = M.notification.SiteNotification(active=True,
+                                               impressions=0,
+                                               content='test1',
+                                               user_role='test2',
+                                               page_regex='test3',
+                                               page_tool_type='test4')
+        ThreadLocalORMSession().flush_all()
+        r = self.app.get('/nf/admin/site_notifications/{}/edit'.format(note._id))
+
+        assert r
+
+        assert (u'selected', u'selected') in r.html.find('form').findAll('option')[1].attrs
+        assert r.form['impressions'].value == '0'
+        assert r.form['content'].value == 'test1'
+        assert r.form['user_role'].value == 'test2'
+        assert r.form['page_regex'].value == 'test3'
+        assert r.form['page_tool_type'].value == 'test4'
+
+        assert 'Edit Site Notification' in r
+        assert 'Active' in r
+        assert 'Impressions' in r
+        assert 'Content' in r
+        assert 'User Role' in r
+        assert 'Page Regex' in r
+        assert 'Page Type' in r
+
+    def test_site_notification_update(self):
+        active = 'True'
+        impressions = '7'
+        content = 'test1'
+        user_role = 'test2'
+        page_regex = 'test3'
+        page_tool_type = 'test4'
+
+        note = M.notification.SiteNotification(active=False,
+                                               impressions=0,
+                                               content='test')
+        ThreadLocalORMSession().flush_all()
+
+        count = M.notification.SiteNotification.query.find().count()
+
+        r = self.app.post('/nf/admin/site_notifications/{}/update'.format(note._id), params=dict(
+            active=active,
+            impressions=impressions,
+            content=content,
+            user_role=user_role,
+            page_regex=page_regex,
+            page_tool_type=page_tool_type))
+        ThreadLocalORMSession().flush_all()
+
+        note = M.notification.SiteNotification.query.find().sort('_id', -1).next()
+
+        assert '/nf/admin/site_notifications' in r.location
+        assert M.notification.SiteNotification.query.find().count() == count
+        assert note.active == bool('True')
+        assert note.impressions == int(impressions)
+        assert note.content == content
+        assert note.user_role == user_role
+        assert note.page_regex == page_regex
+        assert note.page_tool_type == page_tool_type
+
+    def test_site_notification_delete(self):
+        note = M.notification.SiteNotification(active=False,
+                                               impressions=0,
+                                               content='test')
+        ThreadLocalORMSession().flush_all()
+
+        count = M.notification.SiteNotification.query.find().count()
+
+        self.app.get('/nf/admin/site_notifications/{}/delete'.format(note._id))
+        assert M.notification.SiteNotification.query.find().count() == count -1
+        assert M.notification.SiteNotification.query.get(_id=bson.ObjectId(note._id)) is None
+
 
 class TestProjectsSearch(TestController):