summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coip/apps/invitation/__init__.py0
-rw-r--r--coip/apps/invitation/admin.py4
-rw-r--r--coip/apps/invitation/forms.py12
-rw-r--r--coip/apps/invitation/models.py31
-rw-r--r--coip/apps/invitation/views.py73
-rw-r--r--templates/apps/invitation/edit.html1
-rw-r--r--templates/apps/membership/edit.html1
-rw-r--r--templates/apps/membership/membership.html4
-rw-r--r--templates/apps/name/edit.html66
-rw-r--r--templates/apps/name/name.html124
-rw-r--r--templates/apps/userprofile/home.html37
11 files changed, 206 insertions, 147 deletions
diff --git a/coip/apps/invitation/__init__.py b/coip/apps/invitation/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/coip/apps/invitation/__init__.py
diff --git a/coip/apps/invitation/admin.py b/coip/apps/invitation/admin.py
new file mode 100644
index 0000000..722b147
--- /dev/null
+++ b/coip/apps/invitation/admin.py
@@ -0,0 +1,4 @@
+from django.contrib import admin
+from coip.apps.invitation.models import Invitation
+
+admin.site.register(Invitation) \ No newline at end of file
diff --git a/coip/apps/invitation/forms.py b/coip/apps/invitation/forms.py
new file mode 100644
index 0000000..28add9b
--- /dev/null
+++ b/coip/apps/invitation/forms.py
@@ -0,0 +1,12 @@
+'''
+Created on Jun 23, 2010
+
+@author: leifj
+'''
+from django import forms
+from coip.apps.invitation.models import Invitation
+
+class InvitationForm(forms.ModelForm):
+ class Meta:
+ model = Invitation
+ fields = ['email','message','expires'] \ No newline at end of file
diff --git a/coip/apps/invitation/models.py b/coip/apps/invitation/models.py
new file mode 100644
index 0000000..574fc0b
--- /dev/null
+++ b/coip/apps/invitation/models.py
@@ -0,0 +1,31 @@
+'''
+Created on Jun 23, 2010
+
+@author: leifj
+'''
+from django.db import models
+from django.contrib.auth.models import User
+from coip.apps.name.models import Name
+import datetime
+from pprint import pprint
+
+class Invitation(models.Model):
+ '''
+ Invitation to a namespace/group
+ '''
+ inviter = models.ForeignKey(User,related_name='inviter')
+ name = models.ForeignKey(Name,related_name='invitations')
+ email = models.EmailField()
+ message = models.TextField()
+ nonce = models.CharField(unique=True,max_length=255)
+ timecreated = models.DateTimeField(auto_now_add=True)
+ lastupdated = models.DateTimeField(auto_now=True)
+ expires = models.DateTimeField()
+
+ def __unicode__(self):
+ return "%s invited to %s by %s" % (self.email,self.name,self.inviter)
+
+ def send_email(self):
+ pprint("sent email to %s" % (self.email))
+ return
+
diff --git a/coip/apps/invitation/views.py b/coip/apps/invitation/views.py
new file mode 100644
index 0000000..e4c9a53
--- /dev/null
+++ b/coip/apps/invitation/views.py
@@ -0,0 +1,73 @@
+'''
+Created on Jun 23, 2010
+
+@author: leifj
+'''
+from django.contrib.auth.decorators import login_required
+from coip.apps.invitation.models import Invitation
+from coip.apps.invitation.forms import InvitationForm
+from django.http import HttpResponseRedirect, Http404
+from coip.apps.auth.utils import nonce
+from coip.multiresponse import respond_to, render403
+from twisted.python.reflect import ObjectNotFound
+from coip.apps.name.models import Name
+import datetime
+from coip.apps.membership.models import Membership
+from django.shortcuts import get_object_or_404
+
+@login_required
+def invite(request,id):
+ name = None
+ try:
+ name = Name.objects.get(id=id)
+ except ObjectNotFound:
+ raise Http404()
+
+ if not name.has_permission(request.user,'i'):
+ return render403('You are not allowed to invite users to '+name)
+
+ user = request.user
+ if request.method == 'POST':
+ invitation=Invitation(inviter=user,nonce=nonce(),name=name)
+ form = InvitationForm(request.POST,instance=invitation)
+ if form.is_valid():
+ invitation = form.save()
+ invitation.send_email()
+ return HttpResponseRedirect("/name/id/%d" % (name.id))
+ else:
+ exp = datetime.datetime.now()+datetime.timedelta(days=1)
+ invitation=Invitation(message="Please consider joining my group!",expires=exp.strftime("%Y-%m-%d"))
+ form = InvitationForm(instance=invitation);
+
+ return respond_to(request,{'text/html': 'apps/invitation/edit.html'},{'form': form,'name': name,'formtitle': 'Invite to %s' % (name),'submitname': 'Invite User'})
+
+@login_required
+def accept(request,nonce):
+ invitation = None
+ try:
+ invitation = Invitation.objects.get(nonce=nonce)
+ except ObjectNotFound:
+ raise Http404()
+
+ (membership,created) = Membership.objects.get_or_create(user=request.user,name=invitation.name)
+ if created or not membership.enabled:
+ membership.enabled = True
+ membership.save()
+
+ for i in Invitation.objects.filter(user=request.user,name=invitation.name).all:
+ i.delete()
+
+ return HttpResponseRedirect("/membership/%d" % (membership.id))
+
+@login_required
+def cancel(request,id):
+ invitation = get_object_or_404(Invitation,pk=id)
+ name = invitation.name
+
+ if not name.has_permission(request.user,'w'):
+ return render403('You are not allowed to cancel pending invitations to %s' % (name))
+
+ invitation.delete()
+ return HttpResponseRedirect("/name/id/%d" % (name.id))
+
+ \ No newline at end of file
diff --git a/templates/apps/invitation/edit.html b/templates/apps/invitation/edit.html
new file mode 100644
index 0000000..ab833ad
--- /dev/null
+++ b/templates/apps/invitation/edit.html
@@ -0,0 +1 @@
+{% extends "edit.html" %} \ No newline at end of file
diff --git a/templates/apps/membership/edit.html b/templates/apps/membership/edit.html
new file mode 100644
index 0000000..ab833ad
--- /dev/null
+++ b/templates/apps/membership/edit.html
@@ -0,0 +1 @@
+{% extends "edit.html" %} \ No newline at end of file
diff --git a/templates/apps/membership/membership.html b/templates/apps/membership/membership.html
new file mode 100644
index 0000000..e58471c
--- /dev/null
+++ b/templates/apps/membership/membership.html
@@ -0,0 +1,4 @@
+{% extends "tree.html" %}
+{% block content %}
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/apps/name/edit.html b/templates/apps/name/edit.html
index d18cbec..ab833ad 100644
--- a/templates/apps/name/edit.html
+++ b/templates/apps/name/edit.html
@@ -1,65 +1 @@
-{% extends "base.html" %}
-{% block js %}
-<script type="text/javascript">
-$(function() {
- $("#members").accordion({
- header: 'h3'
- });
- $('#tree').jstree({
- 'json_data': {
- 'ajax': {
- 'url': function(n) {
- if (n == -1) {
- return {% if name %}"/rtree/"+{{name.id}}+".json"{% else %}"/rtree.json"{% endif %};
- } else {
- return "/ctree/"+n.attr('id')+".json";
- }
- }
- },
- "progressive_render" : true,
- 'animation': 0,
- },
- 'plugins': ['themeroller','json_data']
- });
-});
-</script>
-{% endblock %}
-{% block headline %}{% if name %}{{name.shortname}}{% else %}(){% endif %}{% endblock %}
-{% block title %}COIP{% if name %} - {{name.shortname}}{% endif %}{% endblock %}
-{% block main %}
-<div style="float: left; width: 30%;">
- {% if name %}
- {% if name.parent %}
- <a href="/name/id/{{name.parent.id}}">.. (up one level)</a>
- {% else %}
- <a href="/name">.. (up one level)</a>
- {% endif %}
- {% endif %}
- <div style="height: 100%;" id="tree"></div>
-</div>
-<div style="float: right; width: 60%; padding-left: 20px;">
- <form method="POST">
- <div class="ui-widget-content ui-corner-all infopanel">
- <h3>{{formtitle}}</h3>
- <table>
- {% for field in form %}
- <tr>
- {% if field.errors %}
- <td colspan="2">{{ field.errors }}</td>
- {% endif %}
- </tr>
- <tr>
- <td>{{ field.label_tag }}</td>
- <td><div class="ui-widget">{{ field }}</div></td>
- </tr>
- {% endfor %}
- </table>
- </div>
- <br/>
- <div class="button">
- <input type="submit" value="{{submitname}}" />
- <input type="button" onClick="document.location='/name/id/{{name.id}}'" value="Cancel"/>
- </div>
- </form>
-</div>
-{% endblock %} \ No newline at end of file
+{% extends "edit.html" %} \ No newline at end of file
diff --git a/templates/apps/name/name.html b/templates/apps/name/name.html
index bc20cd6..3142269 100644
--- a/templates/apps/name/name.html
+++ b/templates/apps/name/name.html
@@ -1,74 +1,80 @@
-{% extends "base.html" %}
-{% block js %}
-<script type="text/javascript">
-$(function() {
- $("#members").accordion({
- header: 'h3'
+{% extends "tree.html" %}
+{% load datehumanize %}
+{% load userdisplay %}
+{% block widgets %}
+ $("#memberships").accordion({
+ header: 'h3',
+ collapsible: true,
+ active: false
});
- $('#tree').jstree({
- 'json_data': {
- 'ajax': {
- 'url': function(n) {
- if (n == -1) {
- return {% if name %}"/rtree/"+{{name.id}}+".json"{% else %}"/rtree.json"{% endif %};
- } else {
- return "/ctree/"+n.attr('id')+".json";
- }
- }
- },
- "progressive_render" : true,
- 'animation': 0,
- },
- 'plugins': ['themeroller','json_data']
+ $("#invitations").accordion({
+ header: 'h3',
+ collapsible: true,
+ active: false
});
-});
-</script>
{% endblock %}
-{% block headline %}{% if name %}{{name.shortname}}{% else %}(){% endif %}{% endblock %}
-{% block title %}COIP{% if name %} - {{name.shortname}}{% endif %}{% endblock %}
-{% block main %}
-<div style="float: left; width: 30%;">
- {% if name %}
- {% if name.parent %}
- <a href="/name/id/{{name.parent.id}}">.. (up one level)</a>
- {% else %}
- <a href="/name">.. (up one level)</a>
- {% endif %}
- {% endif %}
- <div style="height: 100%;" id="tree"></div>
+{% block tools %}
+<div class="ui-widget ui-state-default ui-corner-all" style="padding: 4px; float: left; margin-left: 10px; margin-top: 6px; margin-bottom: 20px;">
+<div class="navlist">
+ <ul>
+ {% if render.edit %}
+ <li style="float: right;"><a class="tip" title="Modify this name" href="/name/{{name.id}}/edit"><span class="ui-icon ui-icon-wrench"></span></a></li>
+ {% endif %}
+ {% if render.delete %}
+ <li style="float: right;"><a class="tip" title="Permanently remove this name" href="/name/{{name.id}}/delete"><span class="ui-icon ui-icon-trash"></span></a></li>
+ {% endif %}
+ {% if render.insert %}
+ <li style="float: right;"><a class="tip" title="Create a new name below this one" href="/name/{{name.id}}/add"><span class="ui-icon ui-icon-plusthick"></span></a></li>
+ {% endif %}
+ {% if render.invite %}
+ <li style="float: right;"><a class="tip" title="Invite user" href="/name/{{name.id}}/invite"><span class="ui-icon ui-icon-heart"></span></a></li>
+ {% endif %}
+ </ul>
+</div>
</div>
-<div style="float: right; width: 60%; padding-left: 20px;">
-{% if name %}
- <div class="ui-widget-content ui-corner-all infopanel">
- <div class="navlist">
- <ul>
- {% if edit %}
- <li style="float: right;"><a class="tip" title="Modify this name" href="/name/edit/id/{{name.id}}"><span class="ui-icon ui-icon-wrench"></span></a>
- {% endif %}
- {% if delete %}
- <li style="float: right;"><a class="tip" title="Permanently remove this name" href="/name/delete/id/{{name.id}}"><span class="ui-icon ui-icon-trash"></span></a>
- {% endif %}
- {% if insert %}
- <li style="float: right;"><a class="tip" title="Create new subordinate name" href="/name/add/id/{{name.id}}"><span class="ui-icon ui-icon-plusthick"></span></a>
- {% endif %}
- </ul>
+{% endblock %}
+{% block content %}
+ {% if name.description %}
+ <div class="ui-widget">
+ <div class="ui-state-highlight ui-corner-all infopanel">
+ {% autoescape off %}
+ <p class="description">{{name.description|safe}}</p>
+ {% endautoescape %}
</div>
- <div class="clear"/>
- <h3>{{name}}</h3>
- <p>{{name.description}}</p>
</div>
{% endif %}
- {% if memberships %}
- <div id="members">
+ <h3>Members</h3>
+ <div id="memberships">
{% for m in memberships.all %}
+ {% if not m.name.hidden %}
<div id="m{{m.id}}" class="{{m.status}}">
- <h3 style="padding-left: 20px;">{{m.user}}</h3>
+ <h3 class="listheader">{{m.user|lastidentifier}}</h3>
+ <div>{{m.user|userdisplay}} ({{m.user|lastidentifier}}) became a member of {{name.shortname}} {{m.timecreated|datehumanize}}.</div>
+ </div>
+ {% endif %}
+ {% empty %}
+ <p>There are no members.</p>
+ {% endfor %}
+ </div>
+ {% if invitations %}
+ <h3>Pending invitations</h3>
+ <div id="invitations">
+ {% for i in invitations.all %}
+ <div id="m{{m.id}}">
+ <h3 class="listheader">{{i.email}}</h3>
<div>
- {{m.user}} has been a member of {{m.name.shortname}} since {{m.timecreated}}<br/>
+ <div class="navlist" style="margin-top: -10px;">
+ <ul>
+ <li style="float: right;"><a class="tip" title="Cancel invitation" href="/invitation/{{i.id}}/cancel"><span class="ui-icon ui-icon-trash"></span></a></li>
+ </ul>
+ </div>
+ <div class="clear"></div>
+ <div>{{i.email}} was invited to {{i.name.shortname}} {{i.timecreated|datehumanize}} by {{i.inviter}}.</div>
</div>
</div>
+ {% empty %}
+ <p>There are no pending invitations.{% if render.invite %}<a class="tip" title="Invite user" href="/name/{{name.id}}/invite">Invite someone!</a>{% endif %}</p>
{% endfor %}
</div>
-{% endif %}
-</div>
+ {% endif %}
{% endblock %} \ No newline at end of file
diff --git a/templates/apps/userprofile/home.html b/templates/apps/userprofile/home.html
index b97b5d8..34673db 100644
--- a/templates/apps/userprofile/home.html
+++ b/templates/apps/userprofile/home.html
@@ -1,33 +1,25 @@
-{% extends "base.html" %}
-{% block js %}
-<script type="text/javascript">
-$(function() {
+{% extends "tree.html" %}
+{% block widgets %}
$("#gravatar").append($.gravatar($('#email').text()));
- $("#memberships").accordion({
+ $("#names").accordion({
header: 'h3',
collapsible: true,
active: false
});
- $("#names").accordion({
+ $("#memberships").accordion({
header: 'h3',
collapsible: true,
active: false
});
-});
-</script>
{% endblock %}
-{% block headline %}{{profile.display_name}}{% endblock %}
-{% block title %}COIP - {{profile.display_name}} - Home{% endblock %}
-{% block main %}
+{% block content %}
<h3>Memberships</h3>
-<div id="memberships" style="width: 60%;">
- {% for m in memberships %}
+<div id="memberships">
+ {% for m in memberships.all %}
<div id="m{{m.id}}" class="{{m.status}}">
- <h3 style="padding-left: 20px;">{{m.name.shortname}}</h3>
+ <h3 class="listheader">{{m.name.shortname}}</h3>
<div>
- You have been a member of {{m.name.shortname}} since {{m.timecreated}}<br/>
- <div>{{m.name.description}}</div></br>
- <a href="/name/id/{{m.name.id}}">More details about {{m.name.shortname}}...</a>
+ You have been a member of <a href="/name/id/{{m.name.id}}">{{m.name.shortname}}</a> since {{m.timecreated}}
</div>
</div>
{% empty %}
@@ -35,17 +27,16 @@ $(function() {
{% endfor %}
</div>
<h3>Names</h3>
-<div id="names" style="width: 60%;">
+<div id="names">
{% for n,p in names %}
- <div id="n{{n.id}}"">
- <h3 style="padding-left: 20px;">{{n.shortname}}</h3>
+ <div id="n{{n.id}}">
+ <h3 class="listheader">{{n.shortname}}</h3>
<div>
- You are allowed to {{p}} {{n.shortname}}<br/>
- <a href="/name/id/{{n.id}}">More details about {{n.shortname}}...</a>
+ You are allowed to {{p}} <a href="/name/id/{{n.id}}">{{n.shortname}}</a>
</div>
</div>
{% empty %}
- <p style="padding: 5px;" class="ui-corner-all ui-state-highlight">You do not own any names</p>
+ <p style="padding: 5px;" class="ui-corner-all ui-state-highlight">You do not control any names</p>
{% endfor %}
</div>
{% endblock %} \ No newline at end of file