← Back to team overview

wikipbx-dev team mailing list archive

Re: address book application

 

Hello,

attached you can find a first try at a shared contacts app for wikipbx.

I'll try to push something to the phone-contacts app tomorrow because i've some merge issues and it's time to go home :)

Comments are appreciated.

thanks,
riccardo
=== added directory 'wikipbx/contacts'
=== added file 'wikipbx/contacts/__init__.py'
=== added file 'wikipbx/contacts/forms.py'
--- wikipbx/contacts/forms.py	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/forms.py	2010-11-02 17:12:12 +0000
@@ -0,0 +1,14 @@
+from django.utils.translation import gettext as _
+from django import forms
+
+from wikipbx.contacts.models import Contact
+
+class ContactForm(forms.ModelForm):
+    class Meta:
+        model = Contact
+        exclude = ('account',)
+
+CONTACTS_EXPORT_CHOICES = (('gigaset', u'Siemens Gigaset'),)
+
+class ExportContactForm(forms.Form):
+    export_type = forms.ChoiceField(choices=CONTACTS_EXPORT_CHOICES, label=_(u"Contacts export format:"))

=== added file 'wikipbx/contacts/models.py'
--- wikipbx/contacts/models.py	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/models.py	2010-11-02 17:07:30 +0000
@@ -0,0 +1,18 @@
+from django.utils.translation import ugettext_lazy as _
+from django.db import models
+from wikipbx.wikipbxweb.models import Account
+
+class Contact(models.Model):
+    name = models.CharField(_(u"name"), max_length=150, unique=True)
+    numbers = models.CharField(_(u"caller ID number"), max_length=25)
+    blacklist = models.BooleanField(_(u"blacklist"), default=False)
+    notes = models.TextField(_(u"notes"), null=True, blank=True)
+    account = models.ForeignKey(Account, verbose_name=_(u"account"))
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta:
+        verbose_name = _(u"contact")
+        verbose_name_plural = _(u"contacts")
+        ordering = ['name']

=== added directory 'wikipbx/contacts/templates'
=== added file 'wikipbx/contacts/templates/contacts.html'
--- wikipbx/contacts/templates/contacts.html	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/templates/contacts.html	2010-11-02 17:08:33 +0000
@@ -0,0 +1,69 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block dashcontent %}
+<h2>
+  <img src="{{ MEDIA_URL }}icons/user.png"/>{% trans "Contacts - This Account" %}
+</h2>
+
+{% if contacts %}
+<div>
+  <form action="/contacts/export/" method="post">
+    {{ export.as_p }}
+    <input type="submit" value={% trans "Export" %}>
+  </form>
+</div>
+
+<table>
+  <thead>
+    <tr>
+      <th>
+	{% trans "Name" %}
+      </th>
+      <th>
+	{% trans "Caller ID number" %}
+      </th>
+      <th>
+	{% trans "Blacklist" %}
+      </th>
+      <th>
+	{% trans "Notes" %}
+      </th>
+      <th>
+	{% trans "Delete" %}
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    {% for contact in contacts %}
+    <tr>
+      <td>
+	<img src="{{ MEDIA_URL }}icons/user_edit.png"/>
+	<a href="{% url contact-edit contact.id %}">{{ contact.name }}</a>
+      </td>
+      <td>
+        {{ contact.numbers }}
+      </td>
+      <td>
+        {{ contact.blacklist }}
+      </td>
+      <td>
+        {{ contact.notes }}
+      </td>
+      <td>
+	<a href="{% url contact-delete contact.id %}">
+	  <img src="{{ MEDIA_URL }}icons/delete.png"/>
+	</a>
+      </td>
+    </tr>
+    {% endfor %}
+  </tbody>
+</table>
+
+{% else %}
+
+<div><img src="{{ MEDIA_URL }}icons/tux.png"/>{% trans "No contacts defined" %}</div>
+
+{% endif %}
+
+{% endblock %}

=== added file 'wikipbx/contacts/templates/edit_contact.html'
--- wikipbx/contacts/templates/edit_contact.html	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/templates/edit_contact.html	2010-11-02 14:32:20 +0000
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block dashcontent %}
+<form method="post">
+  <table>
+    {{ form }}
+    <tr>
+      <td></td>
+      <td><input type="submit" class="button" value={% trans "Update" %}></td>
+    </tr>
+  </table>
+</form>
+{% endblock %}

=== added file 'wikipbx/contacts/tests.py'
--- wikipbx/contacts/tests.py	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/tests.py	2010-11-02 10:21:12 +0000
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+

=== added file 'wikipbx/contacts/urls.py'
--- wikipbx/contacts/urls.py	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/urls.py	2010-11-02 17:00:49 +0000
@@ -0,0 +1,14 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns(
+    'contacts.views',
+
+    url(r'^$', 'contacts', name='contact-list'),
+    url(r'^add/$', 'edit_contact', { 'contact_id': None }, name='contact-add'),
+    url(r'^edit/(?P<contact_id>\d+)/$', 'edit_contact',
+        name='contact-edit'),
+    url(r'^del/(?P<contact_id>\d+)/$', 'del_contact',
+        name='contact-delete'),
+    url(r'^export/$', 'export_contacts',
+        name='contact-export'),
+)

=== added file 'wikipbx/contacts/views.py'
--- wikipbx/contacts/views.py	1970-01-01 00:00:00 +0000
+++ wikipbx/contacts/views.py	2010-11-02 17:31:46 +0000
@@ -0,0 +1,84 @@
+from django.views.decorators.http import require_POST
+from django.utils.translation import gettext as _
+from django.shortcuts import get_object_or_404
+from django.core.urlresolvers import reverse
+from django.views.generic import simple
+from django import http
+
+from wikipbx.wikipbxweb import decorators
+from wikipbx.contacts.models import Contact
+from wikipbx.contacts import forms
+
+import string
+
+@decorators.require_admin
+def contacts(request):
+    account = request.user.get_profile().account
+    contacts = Contact.objects.filter(account=account)
+    export = forms.ExportContactForm()
+    return simple.direct_to_template(
+        request, 'contacts.html', {'contacts': contacts, 'export': export })
+
+@decorators.require_admin
+def edit_contact(request, contact_id):
+    account = request.user.get_profile().account
+    if contact_id is None:
+        contact = Contact(account=account)
+    else:
+        contact = get_object_or_404(Contact, account=account, pk=contact_id)
+
+    if request.method == 'POST':
+        form = forms.ContactForm(request.POST, instance=contact)
+
+        if form.is_valid():
+            contact = form.save()
+
+            msg = _(u"Contact %s saved.") % contact
+            return http.HttpResponseRedirect(
+                reverse('contact-list') + "?infomsg=%s" % msg)
+    else:
+        form = forms.ContactForm(instance=contact)
+
+    return simple.direct_to_template(request, 'edit_contact.html', {'form': form})
+    
+@decorators.require_admin
+def del_contact(request, contact_id):
+    account = request.user.get_profile().account
+    contact = get_object_or_404(Contact, account=account, pk=contact_id)
+    contact.delete()
+    msg = _(u"Contact %s deleted.") % contact
+    return http.HttpResponseRedirect(
+        reverse('contact-list') + "?infomsg=%s" % msg)
+
+VCF_SKELETON = \
+"""BEGIN:VCARD
+VERSION:2.1
+FN: %s
+N: %s
+TEL;HOME:%s
+END:VCARD
+
+"""
+
+def gigaset_export(contacts):
+    vcf = ""
+    for c in contacts:
+        v = VCF_SKELETON % (c.name, c.name, c.numbers)
+        vcf = "%s%s" % (vcf, v)
+    return http.HttpResponse(vcf, mimetype="text/x-vcard")
+
+@decorators.require_admin
+@require_POST
+def export_contacts(request):
+    account = request.user.get_profile().account
+    contacts = Contact.objects.filter(account=account)
+    if True:
+        export_type = request.POST['export_type']
+        if export_type == "gigaset":
+           return gigaset_export(contacts)
+    else:
+        pass
+
+    export = forms.ExportContactForm()
+    return simple.direct_to_template(
+        request, 'contacts.html', {'contacts': contacts, 'export': export })

=== modified file 'wikipbx/settings_template.py'
--- wikipbx/settings_template.py	2010-10-17 15:42:18 +0000
+++ wikipbx/settings_template.py	2010-11-02 15:12:33 +0000
@@ -89,6 +89,7 @@
     # Don't forget to use absolute paths, not relative paths.
     os.path.join(INSTALL_SRC, "wikipbxweb/templates"),
     os.path.join(INSTALL_SRC, "freeswitchxml"),
+    os.path.join(INSTALL_SRC, "contacts/templates"),
 )
 
 INSTALLED_APPS = (
@@ -98,6 +99,7 @@
     'django.contrib.sites',
     'django.contrib.admin',
     'wikipbx.wikipbxweb',
+    'wikipbx.contacts',
 )
 
 TEMPLATE_CONTEXT_PROCESSORS = (

=== modified file 'wikipbx/urls.py'
--- wikipbx/urls.py	2010-09-04 11:48:49 +0000
+++ wikipbx/urls.py	2010-11-02 14:52:07 +0000
@@ -140,6 +140,12 @@
     url(r'^test_mailserver/$', 'test_mailserver', name='email-test'),
 )
 
+# Contacts
+urlpatterns += patterns(
+   '',
+   url(r'^contacts/', include('contacts.urls')),
+)
+
 # Enable static serving only for debug mode. Use your web server as front-end
 # in production.
 if settings.DEBUG:

=== modified file 'wikipbx/wikipbxweb/templates/left_toolbar_base.html'
--- wikipbx/wikipbxweb/templates/left_toolbar_base.html	2010-09-04 19:14:23 +0000
+++ wikipbx/wikipbxweb/templates/left_toolbar_base.html	2010-11-02 15:18:47 +0000
@@ -155,6 +155,15 @@
     <img src="{{ MEDIA_URL }}icons/sound.png"/><a href="{% url soundclip-list %}">{% trans "Manage" %}</a>
   </div>
 </div> 
+
+<div class="header">{% trans "Contacts" %}</div> 
+<div class="indent">            
+  <div class="menu-entry">
+    <img src="{{ MEDIA_URL }}icons/user_add.png"><a href="{% url contact-add %}">{% trans "Add" %}</a>
+  </div>            
+  <div class="menu-entry">
+    <img src="{{ MEDIA_URL }}icons/user.png"/><a href="{% url contact-list %}">{% trans "Manage" %}</a>
+  </div>
 {% endblock %}
 
 {% block help %}


Follow ups

References