Commits

Juha Mustonen committed 87ab2f2

Progress with changerequests

- Added new contact with few fields
- User login/logout

  • Participants
  • Parent commits fb53e39

Comments (0)

Files changed (8)

.idea/dictionaries/juha.xml

+<component name="ProjectDictionaryState">
+  <dictionary name="juha" />
+</component>
 
   # attribute: JSON field
   field_map = {
+    'unit': 'unit',
+    'street': 'street',
+    'zipcode': 'zipCode',
+    'municipality': 'municipality',
     'firstname': 'firstName',
     'lastname': 'lastName',
     'phones': 'phones',
     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()
+      if cr.type == ChangeRequest.TYPE_CREATE:
+	cr.create_contact()
+      elif cr.type == ChangeRequest.TYPE_UPDATE:
+        cr.update_contact()
+      elif cr.type == ChangeRequest.TYPE_DELETE:
+        cr.delete_contact()
       cr.delete()
 
     elif action == 'reject':
       return self.abort(403)
 
     try:
-      data = json.loads(self.request.POST.get('contact'))
-      logging.info(data)
+      data = json.loads(self.request.POST.get('contact', ''))
+      if not data:
+	return self.abort(403)
 
-      c = Contact.get_by_id(long(data['id']))
-      if not c:
-        return self.abort(404)
+      logging.info('RECEIVED CR:')
+      logging.info(data)
 
-      # Create cr with same data as the contact, excluding key/id
-      del data['key']
-      del data['id']
-      cr = ChangeRequest(type=self.types[ctype], contact=c)
-      for attr, field in ContactsHandler.field_map.items():
-        setattr(cr, attr, data.get(field, None))
+      # Update existing
+      if 'id' in data:
+        c = Contact.get_by_id(long(data['id']))
+        if not c:
+          return self.abort(404)
+
+        # Create cr with same data as the contact, excluding key/id
+        del data['key']
+        del data['id']
+        cr = ChangeRequest(type=self.types[ctype], contact=c)
+        for attr, field in ContactsHandler.field_map.items():
+          setattr(cr, attr, data.get(field, None))
+
+      # Create new
+      else:
+        cr = ChangeRequest(type=self.types[ctype])
+        for attr, field in ContactsHandler.field_map.items():
+          setattr(cr, attr, data.get(field, None))
 
       cr.put()
 
       'firstname': self.firstname,
       'lastname': self.lastname,
       'unit': self.unit,
+      'street': self.street,
+      'zipcode': self.zipcode,
+      'municipality': self.municipality,
       'phones': self.phones,
       'group_key': str(self.group.key()) if self.group else None
     }
       'id': self.key().id(),
       'key': str(self.key()),
       'requested': self.requested,
-      'contact_id': self.contact.key().id(),
+      'contact_id': self.contact.key().id() if self.contact else None,
       'type': self.type,
     })
 
     return contact
 
-  def apply(self):
+  def create_contact(self):
+    contact = Contact()
+    for name in self.contact_fields:
+      setattr(contact, name, getattr(self, name))
+    contact.put()
+
+    logging.info('Created new contact: {0}'.format(contact))
+
+  def update_contact(self):
     """
     Applies the changes to contact and returns it back
     """
 
     logging.info('Applied changes to contact: %s' % contact)
 
+  def delete_contact(self):
+    """
+    Applies the changes to contact and returns it back
+    """
+    contact = Contact.get_by_id(self.contact.key().id())
+    contact.delete()
+
+    logging.info('Deleted 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'/user/login', handler='views.LoginHandler', name='login'),
+  webapp2.Route(r'/user/logout', handler='views.LogoutHandler', name='logout'),
   webapp2.Route(r'/request', handler='views.ChangeRequestsHandler', name='request'),
   webapp2.Route(r'/test', handler='views.TestHandler', name='test'),
   webapp2.Route(r'/api/', name='api'),

static/js/base.js

-/**
- * Created with PyCharm.
- * User: juha
- * Date: 11/3/12
- * Time: 10:57 PM
- * To change this template use File | Settings | File Templates.
- */
-function ContactTest() {
-  /*
-  group = db.ReferenceProperty(Group)
-  substituted_by = db.SelfReferenceProperty()
-  firstname = db.StringProperty(required=True)
-  lastname = db.StringProperty(required=True)
-  street = db.PostalAddressProperty()
-  zipcode = db.StringProperty()
-  municipality = db.StringProperty()
-  phones = db.ListProperty(str)
-  email = db.EmailProperty()
-  areas = db.ListProperty(str)
-  created = db.DateTimeProperty(auto_now_add=True)
-  comment = db.StringProperty()
-  available = db.BooleanProperty(default=True)
-  */
 
-}
 function Group(data) {
     this.key = ko.observable(data.key);
 }
     this.street = ko.observable(data.street);
     this.zipCode = ko.observable(data.zipcode);
     this.municipality = ko.observable(data.municipality);
-    this.phones = ko.observable(data.phones);
+    this.phones = ko.observable(data.phones || []);
+
+    this.zipInfo = ko.computed(function(){
+      return (this.zipCode() || "") + " " + (this.municipality() || "");
+    }, this);
 
     this.fullName = ko.computed(function(){
       return this.firstName() + " " + this.lastName();
     }, this);
+
+    this.phonesList = ko.computed(function(){
+      return this.phones().join(', ');
+    }, this);
 }
 
 function ChangeRequest(data) {
   // Data
   var self = this;
 
+  self.addContactToggled = ko.observable(false);
+  self.newContact = ko.observable();
   self.contacts = ko.observableArray([]);
   self.changeRequests = ko.observableArray([]);
   self.changeRequestIds = ko.computed(function(){
     return false;
   };
 
+  self.toggleAddContact = function() {
+      self.newContact(new Contact({}));
+      self.addContactToggled(!self.addContactToggled());
+  };
+
   self.noop = function(contact) {
     // No nothing
     return false;
    * @param type
    */
   self.sendChangeRequest = function(type) {
-    var contact = this;
+    var selectContact = {create: self.newContact(), update: this, delete: this};
+    var contact = selectContact[type];
 
     $.ajax(window.ytl.apiURL + "/request" , {
       type: 'POST',
   clist.load();
 
   window.ko.applyBindings(clist);
+  //window.ko.applyBindings({ytl: window.ytl});
 });

templates/base.html

   <script type="text/javascript" src="/static/js/knockout.min.js"></script>
   <script type="text/javascript" src="/static/js/base.js"></script>
   <script type="text/javascript">
-  window.ytl = {'apiURL': '{{ uri_for('api', _full=True)[0:-1] }}' };
+  window.ytl = {'apiURL': '{{ uri_for('api', _full=True)[0:-1] }}', 'is_admin': {{ 'true' if admin else 'false' }} };
   </script>
   <script type="text/html" id="address-view">
-    <h3 class="unit" data-bind="text: unit"></h3>
+    <h5 class="unit" data-bind="text: unit"></h5>
     <p data-bind="text: street"></p>
-    <p data-bind="text: zipCode"></p>
-    <p data-bind="text: municipality"></p>
+    <p data-bind="text: zipInfo"></p>
   </script>
   <script type="text/html" id="address-edit">
+    <label for="unit">Yksikkö:</label><input id="unit" type="text" data-bind="value: unit"/>
+    <label for="street">Katuosoite:</label><input id="street" type="text" data-bind="value: street"/>
+    <label for="zipcode">Postinumero:</label><input id="zipcode" type="text" data-bind="value: zipCode"/>
+    <label for="municipality">Postitoimipaikka:</label><input id="municipality" type="text" data-bind="value: municipality"/>
+  </script>
+  <script type="text/html" id="address-empty">
     <label for="unit">Yksikkö:</label><input id="unit" type="text" />
+    <label for="street">Katuosoite:</label><input id="street" type="text" />
     <label for="zipcode">Postinumero:</label><input id="zipcode" type="text" />
     <label for="municipality">Postitoimipaikka:</label><input id="municipality" type="text" />
   </script>
   {% endblock %}
 </head>
 <body>
-{% 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>
+      {% if not user %}
+      <li class="{{ 'active' if route == 'login' else '' }}"><a href="{{ uri_for('login') }}">Kirjaudu sisään</a></li>
+      {% else %}
+      <li class="{{ 'active' if route == 'logout' else '' }}"><a href="{{ uri_for('logout') }}">Kirjaudu ulos</a></li>
+      {% endif %}
     </ul>
   </div>
 </div>
-{% endif %}
 {%  block content %}
 
 {% endblock %}

templates/contacts.html

   <div class="alert">
     <a class="btn btn-primary" href="{{ uri_for('test') }}">Generate test data</a>
   </div>
+
+  <h3>Lisää uusi</h3>
+  <p>Kuka vaan voin lisätä</p>
+  <button class="btn" name="start" data-bind="click: $root.toggleAddContact">Aloita lisääminen</button>
+
+  <form name="new" action="{{ uri_for('api-contact-add') }}" method="post" data-bind="visible: $root.addContactToggled, with: $root.newContact">
+    <table class="table">
+      <thead>
+        <tr>
+            <th>Paikka</th>
+            <th>Nimi</th>
+            <th>Nimi</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr class="edit success">
+          <td data-bind="template: {name: 'address-empty'}"></td>
+          <td>
+            <label for="firstName">Etunimi:</label>
+            <input id="firstName" type="text" data-bind="value: firstName"/>
+            <label for="lastName">Sukunimi:</label>
+            <input id="lastName" type="text" data-bind="value: lastName" />
+          </td>
+          <td data-bind="template: {name: 'phones-edit', data: {}}">
+          </td>
+          <td>
+              <button class="btn btn-success" name="save" data-bind="click: $root.sendChangeRequest.bind($root.addContact, 'create')">Lisää</button>
+              <button class="btn btn-inverse" name="cancel" data-bind="click: $root.toggleAddContact">Peruuta</button>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </form>
+
+  <hr />
+
   <h3>Keski-Suomen keskussairaala</h3>
 
-  <form action="{{ uri_for('api-contact-add') }}" method="post">
-  <table class="table table-striped">
+  <form name="edit" action="{{ uri_for('api-contact-add') }}" method="post">
+  <table class="table table-hover">
     <thead>
       <tr>
         <th>Paikka</th>
         <th>Nimi</th>
         <th>Puhelin</th>
-        <th>Sukunimi</th>
+        <th></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><h5 data-bind="text: fullName"></h5></td>
+        <td data-bind="text: phones"></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>
       <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" />
+          <label for="firstName">Etunimi:</label>
+          <input id="firstName" data-bind="value: firstName" type="text" />
+          <label for="firstName">Sukunimi:</label>
+          <input data-bind="value: lastName" type="text" />
         </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-success" name="save" data-bind="click: $root.sendChangeRequest.bind($data, 'update')">Tallenna</button>
+            <button class="btn btn-danger" name="delete" data-bind="click: $root.sendChangeRequest.bind($data, 'delete')">Poista</button>
             <button class="btn btn-inverse" name="cancel" data-bind="click: $root.cancelContactEdit">Peruuta</button>
         </td>
       </tr>
     return self.render_response('contacts.html', **data)
 
 
+class LoginHandler(BaseHandler):
+  def get(self):
+    return self.redirect('_ah/login')
+
+class LogoutHandler(BaseHandler):
+  def get(self):
+    return self.redirect('_ah/logout')
+
+
 class ChangeRequestsHandler(BaseHandler):
   def get(self):
     return self.render_response('requests.html')