Commits

Juha Mustonen  committed fb53e39

Added changes via changerequests

  • Participants
  • Parent commits 7128fd1

Comments (0)

Files changed (9)

 import logging
 import webapp2
 import json
+from webapp2_extras.appengine.users import admin_required
+from google.appengine.api import users
 
 from db import Contact, Group, ChangeRequest
 
 
 
 class JsonHandler(webapp2.RequestHandler):
-  def writejson(self, data):
+  def writejson(self, data='', status=200):
     self.response.headers['Content-Type'] = 'application/json'
+    self.response.status = status
     self.response.out.write(json.dumps(data, cls=ComplexEncoder))
 
 
 class AddContactHandler(JsonHandler):
 
   def post(self):
+    if not users.is_current_user_admin():
+      return self.abort(403)
+
     c = Contact(firstname='foo', lastname='bar', email='foo@domain.com')
     c.put()
 
     """
     Update existing contact
     """
+    if not users.is_current_user_admin():
+      return self.abort(403)
+
     c = Contact.get_by_id(long(id))
     if c:
 
     return self.writejson(list(requests))
 
 
+class ChangeRequestHandler(JsonHandler):
+  def get(self, id):
+    """
+    """
+    cr = ChangeRequest.get_by_id(long(id))
+    if cr:
+      return self.writejson(cr)
+    return self.abort(404)
+
+
+class ResolveChangeRequestHandler(JsonHandler):
+  def post(self, id, action):
+    if not users.is_current_user_admin():
+      return self.abort(403)
+
+    logging.error('--- id: %s, %s' % (id, action))
+
+    cr = ChangeRequest.get_by_id(long(id))
+    if not cr:
+      return self.abort(404)
+
+    if action == 'accept':
+      cr.apply()
+      cr.delete()
+
+    elif action == 'reject':
+      cr.delete()
+      return self.writejson()
+
+    else:
+      return self.abort(403)
+
+
+
 class AddChangeRequestHandler(JsonHandler):
 
   types = {
 __author__ = 'juha'
 
+import logging
+
 from google.appengine.ext import db
 from google.appengine.api import users
 
   comment = db.StringProperty()
   available = db.BooleanProperty(default=True)
 
+  def __str__(self):
+    return '%s %s (%s)' % (self.firstname, self.lastname, self.key().id())
+
   def __json__(self):
     return {
       'id': self.key().id(),
       'key': str(self.key()),
       'firstname': self.firstname,
       'lastname': self.lastname,
+      'unit': self.unit,
       'phones': self.phones,
       'group_key': str(self.group.key()) if self.group else None
     }
   type = db.IntegerProperty(choices=(TYPE_CREATE, TYPE_UPDATE, TYPE_DELETE), required=True)
   note = db.StringProperty()
 
+  contact_fields = ('unit', 'firstname', 'lastname', 'street', 'zipcode', 'municipality', 'phones', 'email', 'areas')
+
   def __json__(self):
     contact = super(ChangeRequest, self).__json__()
     contact.update({
 
     return contact
 
+  def apply(self):
+    """
+    Applies the changes to contact and returns it back
+    """
+    contact = Contact.get_by_id(self.contact.key().id())
+
+    for name in self.contact_fields:
+      setattr(contact, name, getattr(self, name))
+    contact.put()
+
+    logging.info('Applied changes to contact: %s' % contact)
+
 
 class ChangeLog(db.Model):
   created_by = users.get_current_user()
 
 app = webapp2.WSGIApplication([
   webapp2.Route(r'/', handler='views.HomeHandler', name='home'),
+  webapp2.Route(r'/request', handler='views.ChangeRequestsHandler', name='request'),
   webapp2.Route(r'/test', handler='views.TestHandler', name='test'),
   webapp2.Route(r'/api/', name='api'),
   webapp2.Route(r'/api/contact/list', handler='api.ListContactsHandler'),
   webapp2.Route(r'/api/contact/<id:\d+>', handler='api.ContactsHandler', name='api-contact'),
   webapp2.Route(r'/api/contact', handler='api.AddContactHandler', name='api-contact-add'),
-  webapp2.Route(r'/api/request/list', handler='api.ListChangeRequestsHandler', name='api-request-add'),
-  webapp2.Route(r'/api/request/<id:\d+>', handler='api.ChangeRequestHandler', name='api-request'),
+  webapp2.Route(r'/api/request/list', handler='api.ListChangeRequestsHandler', name='api-request-list'),
+  webapp2.Route(r'/api/request/<id:\d+>', handler='api.ChangeRequestHandler', name='api-request', defaults={'id': None}),
+  webapp2.Route(r'/api/request/<id:\d+>/<action>', handler='api.ResolveChangeRequestHandler', name='api-request-resolve', defaults={'action': None}),
   webapp2.Route(r'/api/request', handler='api.AddChangeRequestHandler', name='api-request-add'),
   ], debug=True)
 

File static/css/base.css

 tr.view button.btn:hover {
     opacity: 1;
 }
+
+
+div.navbar span.alert-error {
+  padding: 2px;
+}

File static/js/base.js

 }
 
 function ChangeRequest(data) {
-  this.type = this.type;
+  var self = this;
+
+  // Inherit value
+  var contact = new Contact(data);
+  $.each(contact, function(name, value){
+    self[name] = value;
+  });
 
+  self.type = ko.observable(data.type);
+  self.contactId = ko.observable(data.contact_id);
 }
 
 function ContactListModel() {
 
   self.contacts = ko.observableArray([]);
   self.changeRequests = ko.observableArray([]);
+  self.changeRequestIds = ko.computed(function(){
+    var ids = [];
+    $.each(self.changeRequests(), function(key, request){
+      ids.push(request.contactId());
+    });
+    return ids;
+  });
   self.newTaskText = ko.observable();
   self.currentContact = ko.observable();
 
 
   self.isChangeRequestPending = function(contact) {
     if (typeof contact !== 'undefined') {
-      return $.inArray(contact.id(), self.changeRequests()) !== -1;
+      return $.inArray(contact.id(), self.changeRequestIds()) !== -1;
     }
     return false;
   };
       type: 'POST',
       data: {contact: ko.toJSON(contact), type: type},
       success: function(){
-        self.changeRequests.push(contact.id);
         self.load();
       },
     });
   };
 
   /**
-   * Load status from backend
+   * Load status from backendwarning
    */
   self.load = function() {
     // Load initial state from server, convert it to Task instances, then populate self.tasks
     $.getJSON(window.ytl.apiURL + "/request/list", function(json) {
+
       $.each(json, function(key, cr) {
-        self.changeRequests.push(cr.contact_id);
+        var mappedRequests = $.map(json, function(request) { return new ChangeRequest(request) });
+        self.changeRequests(mappedRequests);
+        // self.changeRequests.push(cr.contact_id);
       });
 
+      // Afte changerequests, retrieve contacts
       $.getJSON(window.ytl.apiURL + "/contact/list", function(json) {
           var mappedContacts = $.map(json, function(contact) { return new Contact(contact) });
           self.contacts(mappedContacts);
     });
   };
 
+  self.resolveRequest = function(action) {
+    var request = this;
+
+    // Post to backend
+    $.ajax(window.ytl.apiURL + "/request/" + request.id() + '/' + action, {
+      type: 'POST',
+      success: function() {
+        // Remove request from changeRequests array
+        var filteredArray = $.grep(self.changeRequests(), function(element){
+          return element.id() != request.id();
+        });
+        self.changeRequests(filteredArray);
+      }
+    });
+  };
+
 }
 
 $(document).ready(function(){

File templates/base.html

         "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-  <title>{{ title }}</title>
+  <title>{% block title %}Yhteystiedot{% endblock %}</title>
   <link rel="stylesheet" href="/static/css/bootstrap.css" />
   <link rel="stylesheet" href="/static/css/base.css" />
   <script type="text/javascript" src="/static/js/jquery.min.js"></script>
   <script type="text/html" id="phones-edit">
     <input id="phone" type="text" />
   </script>
+  {% block scripts %}
+
+  {% endblock %}
 </head>
 <body>
-<h2>Yhteystietolista</h2>
-<div class="alert">
-  <a class="btn btn-primary" href="{{ uri_for('test') }}">Generate test data</a>
+{% if admin %}
+<div class="navbar">
+  <div class="navbar-inner">
+    <a class="brand" href="{{ uri_for('home') }}">YTL</a>
+    <ul class="nav">
+      <li class="{{ 'active' if route == 'home' else '' }}"><a href="{{ uri_for('home') }}">Etusivu</a></li>
+      <li class="{{ 'active' if route == 'request' else '' }}"><a href="{{ uri_for('request') }}">Muutospyynnöt <span class="badge badge-important" data-bind="text: $root.changeRequests().length, visible: $root.changeRequests().length > 0">3</span></a></li>
+    </ul>
+  </div>
 </div>
-<h3>Keski-Suomen keskussairaala</h3>
+{% endif %}
+{%  block content %}
 
-<form action="{{ uri_for('api-contact-add') }}" method="post">
-<table class="table table-striped">
-  <thead>
-    <tr>
-      <th>Paikka</th>
-      <th>Nimi</th>
-      <th>Puhelin</th>
-      <th>Sukunimi</th>
-    </tr>
-  </thead>
-  <tbody data-bind="foreach: contacts">
-    <!-- view -->
-    <tr class="view" data-bind="visible: $data != $root.currentContact()">
-      <td data-bind="template: {name:'address-view', data:$data}"></td>
-      <td data-bind="text: firstName"></td>
-      <td data-bind="text: lastName"></td>
-      <td>
-        <button class="btn btn-primary" data-bind="visible: !$root.isChangeRequestPending($data), click: $parent.editContact, attr: {name: id}">Muokkaa</button>
-        <button class="btn btn-primary" data-bind="visible: $root.isChangeRequestPending($data), disable: $root.isChangeRequestPending($data), click: $root.noop">Muutospyyntö käsittelyssä</button>
-      </td>
-    </tr>
-    <!-- edit -->
-    <tr class="edit" data-bind="visible: $data == $root.currentContact()">
-      <td data-bind="template: {name: 'address-edit', data: $data}"></td>
-      <td>
-        <input data-bind="value: firstName" />
-        <input data-bind="value: lastName" />
-      </td>
-      <td data-bind="template: {name: 'phones-edit', data: phones}">
-      </td>
-      <td>
-          <!--textarea name="contact" data-bind="value: ko.toJSON($data)"></textarea-->
-          <button class="btn btn-danger" name="save" data-bind="click: $root.sendChangeRequest.bind($data, 'update')">Tallenna</button>
-          <button class="btn btn-inverse" name="cancel" data-bind="click: $root.cancelContactEdit">Peruuta</button>
-      </td>
-    </tr>
-  </tbody>
-</table>
-</form>
+{% endblock %}
 </body>
 </html>

File templates/contacts.html

+{% extends "base.html" %}
+
+{% block title %}Keski-Suomen Alueen Puheterapeutit{% endblock %}
+
+{% block scripts %}
+
+{% endblock %}
+
+{% block content %}
+  <h2>Yhteystietolista</h2>
+  <div class="alert">
+    <a class="btn btn-primary" href="{{ uri_for('test') }}">Generate test data</a>
+  </div>
+  <h3>Keski-Suomen keskussairaala</h3>
+
+  <form action="{{ uri_for('api-contact-add') }}" method="post">
+  <table class="table table-striped">
+    <thead>
+      <tr>
+        <th>Paikka</th>
+        <th>Nimi</th>
+        <th>Puhelin</th>
+        <th>Sukunimi</th>
+      </tr>
+    </thead>
+    <tbody data-bind="foreach: contacts">
+      <!-- view -->
+      <tr class="view" data-bind="visible: $data != $root.currentContact()">
+        <td data-bind="template: {name:'address-view', data:$data}"></td>
+        <td data-bind="text: firstName"></td>
+        <td data-bind="text: lastName"></td>
+        <td>
+          <button class="btn btn-primary" data-bind="visible: !$root.isChangeRequestPending($data), click: $parent.editContact, attr: {name: id}">Muokkaa</button>
+          <button class="btn btn-primary" data-bind="visible: $root.isChangeRequestPending($data), disable: $root.isChangeRequestPending($data), click: $root.noop">Muutospyyntö käsittelyssä</button>
+        </td>
+      </tr>
+      <!-- edit -->
+      <tr class="edit" data-bind="visible: $data == $root.currentContact()">
+        <td data-bind="template: {name: 'address-edit', data: $data}"></td>
+        <td>
+          <input data-bind="value: firstName" />
+          <input data-bind="value: lastName" />
+        </td>
+        <td data-bind="template: {name: 'phones-edit', data: phones}">
+        </td>
+        <td>
+            <!--textarea name="contact" data-bind="value: ko.toJSON($data)"></textarea-->
+            <button class="btn btn-danger" name="save" data-bind="click: $root.sendChangeRequest.bind($data, 'update')">Tallenna</button>
+            <button class="btn btn-inverse" name="cancel" data-bind="click: $root.cancelContactEdit">Peruuta</button>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  </form>
+{% endblock %}

File templates/requests.html

+{% extends "base.html" %}
+
+{% block title %}Keski-Suomen Alueen Puheterapeutit - Muutospyynnöt{% endblock %}
+
+{% block content %}
+<h2>Muutospyynnöt</h2>
+<p data-bind="visible: $root.changeRequests().length == 0">Ei muutospyyntöjä käsiteltävänä, <a href="{{ uri_for('home') }}">voit tehdä niitä listauksesta</a></p>
+
+<section data-bind="visible: $root.changeRequests().length > 0">
+  <p>Muutospyynnöt jotka odottavat käsittelyä</p>
+  <table class="table" data-bind="visible: $root.changeRequests().length > 0">
+    <thead>
+      <tr>
+        <th>Paikka</th>
+        <th>Nimi</th>
+        <th>Puhelin</th>
+        <th>Sukunimi</th>
+      </tr>
+    </thead>
+    <tbody data-bind="foreach: changeRequests">
+      <!-- view -->
+      <tr class="view">
+        <td data-bind=""></td>
+        <td data-bind="text: firstName"></td>
+        <td data-bind="text: lastName"></td>
+        <td>
+          <button class="btn btn-success" data-bind="click: $parent.resolveRequest.bind($data, 'accept'), attr: {name: id}">Hyväksy</button>
+          <button class="btn btn-danger" data-bind="click: $root.resolveRequest.bind($data, 'reject')">Hylkää</button>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+</section>
+
+{% endblock %}
 from webapp2_extras.jinja2 import get_jinja2
 from webapp2 import redirect, uri_for
 
+from google.appengine.api import users
+
+
 from db import Contact
 
 
 
     def render_response(self, _template, **context):
         # Renders a template and writes the result to the response.
+
         default_context = {
-          'uri_for': uri_for
+          'uri_for': uri_for,
+          'user': users.get_current_user(),
+          'admin' : users.is_current_user_admin(),
+          'route': self.request.route.name
         }
         default_context.update(context)
 
     #template = jinja_env.get_template('base.html')
     #self.response.out.write(template.render(name='John Doe', title='Testing'))
     data = {'name': 'John!'}
-    return self.render_response('base.html', **data)
+    return self.render_response('contacts.html', **data)
+
+
+class ChangeRequestsHandler(BaseHandler):
+  def get(self):
+    return self.render_response('requests.html')
 
 
 class TestHandler(BaseHandler):