Revision ccd822a8
b/invitations/invitations.py | ||
---|---|---|
1 | 1 |
from django import forms |
2 | 2 |
from django.conf import settings |
3 | 3 |
from django.db import transaction |
4 |
from django.forms.util import ErrorList |
|
4 | 5 |
from django.http import HttpResponse, HttpResponseRedirect |
5 | 6 |
from django.shortcuts import render_to_response |
7 |
from django.template import Template |
|
8 |
from django.template.context import Context, RequestContext |
|
6 | 9 |
from django.template.loader import render_to_string |
7 | 10 |
from synnefo.api.common import method_not_allowed |
8 | 11 |
from synnefo.db.models import Invitations, SynnefoUser |
9 | 12 |
from synnefo.logic import users |
10 | 13 |
|
11 | 14 |
class InvitationForm(forms.Form): |
12 |
emails = forms.Textarea
|
|
13 |
|
|
14 |
def send_emails(self, request): |
|
15 |
if request.method == 'POST': # If the form has been submitted...
|
|
16 |
form = InvitationForm(request.POST) # A form bound to the POST data
|
|
17 |
if form.is_valid(): # All validation rules pass
|
|
18 |
# Process the data in form.cleaned_data
|
|
19 |
# ...
|
|
20 |
return HttpResponseRedirect('/thanks/') # Redirect after POST
|
|
21 |
else:
|
|
22 |
form = InvitationForm() # An unbound form
|
|
15 |
name = forms.CharField(required=True)
|
|
16 |
email = forms.EmailField(required=True) |
|
17 |
|
|
18 |
def send_emails(request):
|
|
19 |
if request.method == 'POST':
|
|
20 |
form = InvitationForm(request.POST)
|
|
21 |
if form.is_valid():
|
|
22 |
# Process the data in form.cleaned_data
|
|
23 |
return HttpResponseRedirect('/invitation/')
|
|
24 |
else: |
|
25 |
form = InvitationForm() # An unbound form |
|
23 | 26 |
|
24 |
return render_to_response('invitation.html', {'form': form,})
|
|
27 |
return render_to_response('invitations.html', {'form': form,})
|
|
25 | 28 |
|
26 | 29 |
def inv_demux(request): |
27 | 30 |
if request.method == 'GET': |
28 | 31 |
invitations = Invitations.objects.filter(source = request.user) |
29 |
data = render_to_string('invitations.html', {'invitations': invitations}) |
|
32 |
form = InvitationForm() |
|
33 |
data = render_to_string('invitations.html', {'invitations': invitations, 'form':form}) |
|
30 | 34 |
return HttpResponse(data) |
31 | 35 |
elif request.method == 'POST': |
32 |
f = InvitationForm(request)
|
|
36 |
return send_emails(request)
|
|
33 | 37 |
else: |
34 | 38 |
method_not_allowed(request) |
35 | 39 |
|
b/invitations/templates/invitations.html | ||
---|---|---|
4 | 4 |
<head> |
5 | 5 |
<title>Αποστολή προσκλήσεων σε χρήστες</title> |
6 | 6 |
<script src="/static/jquery.tools.min.js"></script> |
7 |
|
|
7 |
<script src="/static/jquery.dynamicField.js"></script> |
|
8 | 8 |
<script type="text/javascript"> |
9 | 9 |
|
10 | 10 |
$(document).ready(function() { |
11 |
$("#emaillist").click(function(){ |
|
12 |
$("#emaillist").text(''); |
|
13 |
}); |
|
11 |
$("#invform #removable-name-container-1").dynamicField(); |
|
14 | 12 |
}); |
15 | 13 |
|
16 | 14 |
</script> |
17 | 15 |
|
18 | 16 |
<style type="text/css"> |
19 |
|
|
17 |
|
|
20 | 18 |
</style> |
21 | 19 |
</head> |
22 | 20 |
<body> |
23 |
{% if error_message %}<div id="error"><strong>{{ error_message }}</strong></div>{% endif %} |
|
24 |
|
|
25 |
<form id="" action="/invitations/" method="post"> |
|
26 |
{% csrf_token %} |
|
27 |
<label for="emaillist">Email για αποστολή προσκλήσεων (διαθέσιμες: |
|
28 |
<span id="remaining">{{ invitations.count }}</span> |
|
29 |
) |
|
30 |
</label> |
|
31 |
<textarea id="emaillist" rows="24" cols="80"> |
|
32 |
Εισάγετε τη λίστα των διευθύνσεων email στις οποίες θέλετε να αποσταλούν προσκλήσεις, μια σε κάθε γραμμή. |
|
33 |
Οι διευθύνσεις θα πρέπει να είναι στη μορφή: Όνομα Επίθετο <uname@domain.tld>, για παράδειγμα: |
|
34 |
|
|
35 |
Donald Knuth <knuth@stanford.edu> |
|
36 |
Dennis Ritchie <drm@bell.com> |
|
37 |
|
|
38 |
</textarea> |
|
39 |
<br/> |
|
40 |
<input type="submit" value="Αποστολή Προσκλήσεων" /> |
|
21 |
<form action="/invitation/" method="post" id="invform"> |
|
22 |
{% csrf_token %} |
|
23 |
<div id="fieldheaders"> |
|
24 |
<span id="field_name_name">Όνομα</span> |
|
25 |
<span id="field_email_name">Email</span> |
|
26 |
</div> |
|
27 |
<div id="fields"> |
|
28 |
<div id="removable-name-container-1" class="removable-field-row"> |
|
29 |
<label for="name_1">Name</label> |
|
30 |
<input type="text" name="name_1" id="name_1" value="" class="textInput removable" /> |
|
31 |
<label for="email_1">Email</label> |
|
32 |
<input type="text" name="email_1" id="email_1" value="" class="textInput removable" /> |
|
33 |
<img src="/static/spacer.gif" width="16" height="16" alt="" title="Remove This Item" class="" /> |
|
34 |
</div> |
|
35 |
|
|
36 |
<div id="add-name-container" class="add-field-container"> |
|
37 |
<span class="add-field-trigger"> |
|
38 |
<img src="/static/add.gif" alt="" title="Add New Item" /> |
|
39 |
Add Row |
|
40 |
</span> |
|
41 |
</div> |
|
42 |
</div> |
|
43 |
<p><input type="submit" value="Αποστολή Προσκλήσεων" /></p> |
|
41 | 44 |
</form> |
42 | 45 |
|
43 | 46 |
<div id="invsent"> |
b/invitations/urls.py | ||
---|---|---|
2 | 2 |
|
3 | 3 |
|
4 | 4 |
urlpatterns = patterns('synnefo.invitations.invitations', |
5 |
(r'^$', 'inv_demux') |
|
5 |
(r'^$', 'inv_demux'), |
|
6 |
(r'^/$', 'inv_demux'), |
|
6 | 7 |
) |
b/ui/static/jquery.dynamicField.js | ||
---|---|---|
1 |
/* |
|
2 |
* jQuery dynamicField plugin |
|
3 |
* Copyright 2009, Matt Quackenbush (http://www.quackfuzed.com/) |
|
4 |
* |
|
5 |
* Find usage demos at http://www.quackfuzed.com/demos/jQuery/dynamicField/index.cfm) |
|
6 |
* |
|
7 |
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) |
|
8 |
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. |
|
9 |
* |
|
10 |
* Version: 1.0 |
|
11 |
* Date: 8/13/2009 |
|
12 |
*/ |
|
13 |
;(function($) { |
|
14 |
$.fn.dynamicField = function(options) { |
|
15 |
if ( $(this).attr("id") == undefined ) { |
|
16 |
alert("The dynamicField plugin could not be initialized.\n\nPlease check the selector."); |
|
17 |
return $; |
|
18 |
} |
|
19 |
|
|
20 |
var f = $(this); |
|
21 |
|
|
22 |
var settings = $.extend({ |
|
23 |
maxFields: 5, |
|
24 |
removeImgSrc: "/static/cross.png", |
|
25 |
spacerImgSrc: "/static/spacer.gif", |
|
26 |
addTriggerClass: "add-field-trigger", |
|
27 |
removeImgClass: "remove-field-trigger", |
|
28 |
hideClass: "hide", |
|
29 |
cloneContainerId: f.attr("id").replace(/^(.+)([_-][0-9]+)$/,"$1"), |
|
30 |
rowContainerClass: f.attr("class"), |
|
31 |
labelText: f.children("label") |
|
32 |
.html(), |
|
33 |
baseName: f.children("input") |
|
34 |
.attr("name") |
|
35 |
.replace(/^(.+[_-])([0-9]+)$/,"$1"), |
|
36 |
baseNames: baseNames(), |
|
37 |
addContainerId: "add-" + f.children("input") |
|
38 |
.attr("name") |
|
39 |
.replace(/^(.+)([_-][0-9]+)$/,"$1") |
|
40 |
.replace(/_/g,"-") + "-container" |
|
41 |
},options); |
|
42 |
|
|
43 |
var getFields = function() { |
|
44 |
return $("div." + settings.rowContainerClass); |
|
45 |
}; |
|
46 |
|
|
47 |
function baseNames() { |
|
48 |
var names = new Array(); |
|
49 |
$.each(f.children("input"), function(index, child){ |
|
50 |
var name = child.name.replace(/^(.+[_-])([0-9]+)$/,"$1") |
|
51 |
names.push(name); |
|
52 |
}); |
|
53 |
return names; |
|
54 |
} |
|
55 |
|
|
56 |
// handle hide/show, etc |
|
57 |
var addRemoveBtnCk = function() { |
|
58 |
var fields = getFields(); |
|
59 |
var len = fields.length; |
|
60 |
|
|
61 |
fields.each(function(i,elem) { |
|
62 |
$(elem) |
|
63 |
.children("img") |
|
64 |
.attr({ |
|
65 |
"src":(len == 1) ? settings.spacerImgSrc : settings.removeImgSrc, |
|
66 |
"class":(len == 1) ? "" : settings.removeImgClass |
|
67 |
}); |
|
68 |
}); |
|
69 |
|
|
70 |
if ( len > (settings.maxFields-1) ) { |
|
71 |
$("div#" + settings.addContainerId).addClass(settings.hideClass); |
|
72 |
} else { |
|
73 |
$("div#" + settings.addContainerId).removeClass(settings.hideClass); |
|
74 |
} |
|
75 |
}; |
|
76 |
|
|
77 |
// handle field removal |
|
78 |
$("img." + settings.removeImgClass).live("click",function() { |
|
79 |
// remove the selected row |
|
80 |
$(this).parent("div." + settings.rowContainerClass).remove(); |
|
81 |
|
|
82 |
// rebrand the remaining fields sequentially |
|
83 |
getFields().each(function(i,elem) { |
|
84 |
var pos = new Number(i+1); |
|
85 |
var d = $(elem) |
|
86 |
.attr("id",settings.cloneContainerId + "-" + pos); |
|
87 |
|
|
88 |
d.children("label") |
|
89 |
.attr("for",settings.baseName + pos) |
|
90 |
.html((pos > 1) ? "" : settings.labelText); |
|
91 |
|
|
92 |
d.children("input") |
|
93 |
.attr({ |
|
94 |
"id":settings.baseName + pos, |
|
95 |
"name":settings.baseName + pos |
|
96 |
}); |
|
97 |
}); |
|
98 |
|
|
99 |
addRemoveBtnCk(); |
|
100 |
}); |
|
101 |
|
|
102 |
// handle field add |
|
103 |
$("div#" + settings.addContainerId + " span." + settings.addTriggerClass).click(function() { |
|
104 |
var len = getFields().length; |
|
105 |
var pos = new Number(len+1); |
|
106 |
var newDiv = f |
|
107 |
.clone() |
|
108 |
.attr("id",settings.cloneContainerId + "-" + pos) |
|
109 |
.addClass(settings.rowContainerClass); |
|
110 |
|
|
111 |
newDiv.children("label") |
|
112 |
.attr("for",settings.baseName + pos) |
|
113 |
.html(""); |
|
114 |
|
|
115 |
newDiv.children("input") |
|
116 |
.attr({ |
|
117 |
"id":settings.baseName + pos, |
|
118 |
"name":settings.baseName + pos, |
|
119 |
"value":"" |
|
120 |
}); |
|
121 |
|
|
122 |
newDiv.children("img") |
|
123 |
.attr("src",settings.removeImgSrc); |
|
124 |
|
|
125 |
if ( len > 0 ) { |
|
126 |
$("div#" + settings.cloneContainerId + "-" + len).after(newDiv); |
|
127 |
} else { |
|
128 |
$("div#" + settings.addContainerId).before(newDiv); |
|
129 |
} |
|
130 |
|
|
131 |
addRemoveBtnCk(); |
|
132 |
}); |
|
133 |
}; |
|
134 |
})(jQuery); |
Also available in: Unified diff