Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nuages
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etch
nuages
Commits
9b45de72
Commit
9b45de72
authored
May 12, 2013
by
Christophe Siraut
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cleanup
parent
4a168dd6
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
98 additions
and
79 deletions
+98
-79
Makefile
Makefile
+11
-1
README
README
+17
-11
accounts/admin.py
accounts/admin.py
+1
-1
accounts/models.py
accounts/models.py
+3
-1
accounts/views.py
accounts/views.py
+14
-12
settings.py
settings.py
+1
-1
sondage/admin.py
sondage/admin.py
+1
-1
sondage/forms.py
sondage/forms.py
+15
-3
sondage/models.py
sondage/models.py
+8
-14
sondage/views.py
sondage/views.py
+27
-34
No files found.
Makefile
View file @
9b45de72
clean
:
find
.
-name
"*.pyc"
-exec
rm
{}
\;
find
.
-name
"*~"
-exec
rm
{}
\;
find
.
-name
".svn"
-exec
rm
-r
{}
\;
update
:
git pull
--rebase
python manage.py syncdb
--noinput
python manage.py collectstatic
--noinput
chown
-R
www-data .
translation
:
#django-admin.py makemessages -l fr
python manage.py makemessages
-a
python manage.py compilemessages
lint
:
#django-lint
pylint
--generated-members
=
objects,_meta,id sondage
pylint
--generated-members
=
objects,_meta,id accounts
README
View file @
9b45de72
...
...
@@ -22,11 +22,11 @@ Create/update a translation file:
Edit and translate the translation file:
#
gedit
locale/fr/LC_MESSAGES/django.po
#
vi
locale/fr/LC_MESSAGES/django.po
Compile translated messages:
Compile translated messages
/update a translation file
:
#
django-admin compilemessages
#
make translation
Fast installation
=================
...
...
@@ -37,9 +37,8 @@ Clone nuages archive somewhere in your home folder
# cd
# git clone http://git.domainepublic.net/git/nuages.git
You can have local customizations in the local_settings.py file
You can have local customizations in the local_settings.py file
(and avoid modify the original settings.py)
# cp settings.py local_settings.py
# vi local_settings.py
Build nuages database
...
...
@@ -61,10 +60,9 @@ Copy nuages to /usr/local/lib/nuages
# cd /usr/local/lib
# git clone http://git.domainepublic.net/git/nuages.git
Optionally edit project setings and set DEBUG option to False
You can have local customizations in the local_settings.py file. Optionally set DEBUG option to False.
# cd /usr/local/lib/nuages
# vi settings.py
# vi local_settings.py
Build nuages database
...
...
@@ -94,7 +92,7 @@ There are several ways to configure Apache and python, we recommend wsgi, simply
Adapt the path in file apache/django.wsgi
Fix
permission for apache user
Set
permission for apache user
sudo chown -R www-data /usr/local/lib/nuages
...
...
@@ -114,8 +112,15 @@ Another option is to add attributes in settings.py, this make email work only wh
EMAIL_HOST_PASSWORD = 'password'
EMAIL_USE_TLS = False
Migrations
==========
Update
======
In order to update your nuages installation, you can issue:
# make update
Migration
=========
When models change, we need to perform some manual steps to keep existing data:
...
...
@@ -126,3 +131,4 @@ When models change, we need to perform some manual steps to keep existing data:
# ./manage.py reset sondage accounts
# ./manage.py syncdb
# ./manage.py loaddata < fixture/*.json
accounts/admin.py
View file @
9b45de72
from
models
import
*
from
accounts.models
import
UserProfile
from
django.contrib
import
admin
admin
.
site
.
register
(
UserProfile
)
accounts/models.py
View file @
9b45de72
from
django.db
import
models
from
django.contrib.auth.models
import
User
from
django.contrib.auth.signals
import
user_logged_in
from
django.core.exceptions
import
ObjectDoesNotExist
class
UserProfile
(
models
.
Model
):
user
=
models
.
OneToOneField
(
User
)
email_notifications
=
models
.
BooleanField
()
def
login_handler
(
user
,
**
kwargs
):
"""Verify user profile exists"""
try
:
profile
=
UserProfile
.
objects
.
get
(
user
=
user
)
except
:
except
ObjectDoesNotExist
:
profile
=
UserProfile
(
user
=
user
)
profile
.
save
()
return
...
...
accounts/views.py
View file @
9b45de72
from
django.conf
import
settings
from
django.shortcuts
import
render
,
HttpResponseRedirect
from
django.core.urlresolvers
import
reverse
from
django.contrib.auth.models
import
User
from
django.contrib.auth.decorators
import
login_required
from
django.utils.translation
import
ugettext_lazy
from
accounts.forms
import
UserProfileForm
def
_
(
string
):
"""ugettext_lazy shortcut"""
return
unicode
(
ugettext_lazy
(
string
))
def
email_notify
(
poll
,
voter
):
subject
=
_
(
"Nuages email notification"
)
message
=
_
(
"User %s has voted."
)
%
voter
message
+=
"
\n\n
"
message
+=
_
(
"The link to your poll: %s"
)
%
poll
.
link
message
+=
"
\n\n
"
message
+=
_
(
"Current results:"
)
message
+=
"
\n\n
"
for
choice
in
poll
.
choice_set
.
all
():
message
+=
"%s: %i
\n
"
%
(
choice
.
choice
,
choice
.
votecount
)
poll
.
user
.
email_user
(
subject
,
message
,
settings
.
DEFAULT_FROM_EMAIL
)
"""Send email notification"""
subject
=
_
(
"Nuages email notification"
)
message
=
_
(
"User %s has voted."
)
%
voter
message
+=
"
\n\n
"
message
+=
_
(
"The link to your poll: %s"
)
%
poll
.
link
message
+=
"
\n\n
"
message
+=
_
(
"Current results:"
)
message
+=
"
\n\n
"
for
choice
in
poll
.
choice_set
.
all
():
message
+=
"%s: %i
\n
"
%
(
choice
.
choice
,
choice
.
votecount
)
poll
.
user
.
email_user
(
subject
,
message
,
settings
.
DEFAULT_FROM_EMAIL
)
@
login_required
def
profile
(
request
):
"""profile view"""
if
request
.
method
==
'POST'
:
form
=
UserProfileForm
(
request
.
POST
)
if
form
.
is_valid
():
for
k
,
v
in
form
.
cleaned_data
.
iteritems
():
for
k
,
v
in
form
.
cleaned_data
.
iteritems
():
setattr
(
request
.
user
.
userprofile
,
k
,
v
)
request
.
user
.
userprofile
.
save
()
return
HttpResponseRedirect
(
reverse
(
'home'
))
...
...
settings.py
View file @
9b45de72
...
...
@@ -44,7 +44,7 @@ LANGUAGES = (
(
'fr'
,
'Francais'
),
(
'en'
,
'English'
),
(
'nl'
,
'Nederlands'
),
(
'ca'
,
'Catalan'
)
;
(
'ca'
,
'Catalan'
)
)
SITE_ID
=
1
...
...
sondage/admin.py
View file @
9b45de72
from
models
import
*
from
sondage.models
import
Poll
,
Choice
,
Bulletin
,
Vote
from
django.contrib
import
admin
admin
.
site
.
register
(
Poll
)
...
...
sondage/forms.py
View file @
9b45de72
...
...
@@ -10,8 +10,16 @@ class PollForm(forms.ModelForm):
fields
=
(
'title'
,
'description'
)
class
ChoiceForm
(
forms
.
ModelForm
):
choice
=
forms
.
DateTimeField
(
widget
=
forms
.
DateTimeInput
(
format
=
'%d-%m-%Y %H:%M'
,
attrs
=
{
'class'
:
'hasdatepicker'
,
'size'
:
'18'
,}),
input_formats
=
[
'%d-%m-%Y %H:%M'
])
details
=
forms
.
CharField
(
required
=
False
,
max_length
=
'200'
,
widget
=
forms
.
TextInput
(
attrs
=
{
'size'
:
'32'
,}))
choice
=
forms
.
DateTimeField
(
widget
=
forms
.
DateTimeInput
(
format
=
'%d-%m-%Y %H:%M'
,
attrs
=
{
'class'
:
'hasdatepicker'
,
'size'
:
'18'
,}),
input_formats
=
[
'%d-%m-%Y %H:%M'
]
)
details
=
forms
.
CharField
(
required
=
False
,
max_length
=
'200'
,
widget
=
forms
.
TextInput
(
attrs
=
{
'size'
:
'32'
,})
)
class
Meta
:
model
=
Choice
exclude
=
(
'poll'
,
'votecount'
)
...
...
@@ -21,7 +29,11 @@ class BulletinForm(forms.ModelForm):
model
=
Bulletin
class
VoteForm
(
forms
.
ModelForm
):
comment
=
forms
.
CharField
(
required
=
False
,
max_length
=
80
,
widget
=
forms
.
TextInput
(
attrs
=
{
'class'
:
'comment'
}))
comment
=
forms
.
CharField
(
required
=
False
,
max_length
=
80
,
widget
=
forms
.
TextInput
(
attrs
=
{
'class'
:
'comment'
})
)
choice
=
forms
.
CharField
()
class
Meta
:
model
=
Vote
...
...
sondage/models.py
View file @
9b45de72
...
...
@@ -11,13 +11,13 @@ def _createId():
class
Poll
(
models
.
Model
):
# Override django id AutoField with randomly generatyed hash
id
=
models
.
CharField
(
primary_key
=
True
,
unique
=
True
,
max_length
=
8
,
default
=
_createId
)
title
=
models
.
CharField
(
_
(
'Title'
),
max_length
=
80
)
id
=
models
.
CharField
(
primary_key
=
True
,
unique
=
True
,
max_length
=
8
,
default
=
_createId
)
title
=
models
.
CharField
(
_
(
'Title'
),
max_length
=
80
)
pub_date
=
models
.
DateField
(
auto_now_add
=
True
)
upd_date
=
models
.
DateField
(
auto_now
=
True
)
author
=
models
.
CharField
(
max_length
=
40
)
description
=
models
.
CharField
(
max_length
=
300
)
user
=
models
.
ForeignKey
(
User
,
blank
=
True
,
null
=
True
)
user
=
models
.
ForeignKey
(
User
,
blank
=
True
,
null
=
True
)
def
__unicode__
(
self
):
return
self
.
title
...
...
@@ -29,16 +29,16 @@ class Poll(models.Model):
class
Choice
(
models
.
Model
):
poll
=
models
.
ForeignKey
(
Poll
)
choice
=
models
.
DateTimeField
()
details
=
models
.
CharField
(
max_length
=
200
,
blank
=
True
)
votecount
=
models
.
IntegerField
(
default
=
0
,
blank
=
True
)
details
=
models
.
CharField
(
max_length
=
200
,
blank
=
True
)
votecount
=
models
.
IntegerField
(
default
=
0
,
blank
=
True
)
class
Meta
:
ordering
=
[
'choice'
]
def
__unicode__
(
self
):
return
str
(
self
.
choice
)
# hacky?
class
Bulletin
(
models
.
Model
):
poll
=
models
.
ForeignKey
(
Poll
,
editable
=
False
)
voter
=
models
.
CharField
(
""
,
max_length
=
40
)
poll
=
models
.
ForeignKey
(
Poll
,
editable
=
False
)
voter
=
models
.
CharField
(
""
,
max_length
=
40
)
def
__unicode__
(
self
):
return
self
.
voter
...
...
@@ -47,15 +47,9 @@ class Vote(models.Model):
choice
=
models
.
ForeignKey
(
Choice
)
bulletin
=
models
.
ForeignKey
(
Bulletin
)
voice
=
models
.
BooleanField
()
comment
=
models
.
CharField
(
max_length
=
80
,
blank
=
True
)
comment
=
models
.
CharField
(
max_length
=
80
,
blank
=
True
)
class
Meta
:
ordering
=
[
'choice'
]
def
__unicode__
(
self
):
return
str
(
self
.
voice
)
"""
# First, define the Manager subclass.
class VoteBuletin(models.Manager):
def get_query_set(self):
return super(VoteBuletin, self).get_query_set().filter(author='Roald Dahl')
"""
sondage/views.py
View file @
9b45de72
# Here are the views for sondage
import
datetime
from
django.http
import
HttpResponse
,
HttpResponseRedirect
from
django.shortcuts
import
get_object_or_404
,
render_to_response
from
django.core.urlresolvers
import
reverse
...
...
@@ -15,29 +12,26 @@ from django.utils.translation import ugettext_lazy as _
from
django.conf
import
settings
from
accounts.views
import
email_notify
from
accounts.forms
import
UserProfileForm
from
django.core.exceptions
import
ObjectDoesNotExist
def
new
(
request
):
if
request
.
method
==
'POST'
:
# If the form has been submitted...
if
request
.
method
==
'POST'
:
if
request
.
user
.
is_authenticated
():
instance
=
Poll
(
author
=
str
(
request
.
user
),
user
=
request
.
user
)
else
:
instance
=
Poll
(
author
=
str
(
request
.
user
))
form
=
PollForm
(
request
.
POST
,
instance
=
instance
)
# A form bound to the POST data
if
form
.
is_valid
():
# All validation rules pass
poll_id
=
form
.
cleaned_data
.
get
(
'title'
)
# Process the data in form.cleaned_data
new_poll
=
form
.
save
()
form
=
PollForm
(
request
.
POST
,
instance
=
instance
)
if
form
.
is_valid
():
new_poll
=
Poll
(
**
form
.
cleaned_data
).
save
()
key
=
'is_'
+
new_poll
.
id
+
'_author'
request
.
session
[
key
]
=
True
# This writes cookie
redir
=
'/'
+
str
(
new_poll
.
id
)
+
'/edit/choices/'
return
HttpResponseRedirect
(
redir
)
else
:
form
=
PollForm
()
# An unbound form
return
render_to_response
(
'sondage/poll_form.html'
,
{
'form'
:
form
},
context_instance
=
RequestContext
(
request
))
return
render_to_response
(
'sondage/poll_form.html'
,
{
'form'
:
form
},
context_instance
=
RequestContext
(
request
))
@
login_required
def
secure_update_object
(
*
args
,
**
kwargs
):
...
...
@@ -58,7 +52,7 @@ def get_ordereditem_formset(form, formset=BaseInlineFormSet, **kwargs):
def
editchoices
(
request
,
poll_id
):
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
language_code
=
request
.
LANGUAGE_CODE
error_message
=
''
if
poll
.
author
==
'AnonymousUser'
:
# Anonymous wants to edit his new poll
...
...
@@ -87,11 +81,10 @@ def editchoices(request, poll_id):
this_choice
=
instance
[
'choice'
]
if
not
instance
.
get
(
'DELETE'
):
try
:
choice
=
Choice
.
objects
.
get
(
poll
=
poll
,
choice
=
instance
[
'choice'
])
choice
=
Choice
.
objects
.
get
(
poll
=
poll
,
choice
=
instance
[
'choice'
])
choice
.
details
=
instance
[
'details'
]
choice
.
save
()
except
(
KeyError
,
Choice
.
DoesNotExist
):
except
ObjectDoesNotExist
:
choice
=
Choice
(
poll
=
poll
,
choice
=
instance
[
'choice'
],
details
=
instance
[
'details'
])
choice
.
save
()
# If bulletins for this poll existed before edition
...
...
@@ -102,7 +95,7 @@ def editchoices(request, poll_id):
nvote
.
save
()
else
:
try
:
choice
=
Choice
.
objects
.
get
(
poll
=
poll
,
choice
=
this_choice
)
choice
=
Choice
.
objects
.
get
(
poll
=
poll
,
choice
=
this_choice
)
"""
Removing a Choice will remove all childeren Vote objects.
When Django deletes an object, it emulates the behavior of
...
...
@@ -110,7 +103,7 @@ def editchoices(request, poll_id):
objects which had foreign keys pointing at the object to be
deleted will be deleted along with it."""
choice
.
delete
()
except
:
except
:
pass
except
:
# probably an empty datefield?
...
...
@@ -120,7 +113,7 @@ def editchoices(request, poll_id):
else
:
#vforms=OrderedItemFormset(request.POST, instance=poll)
error_message
=
_
(
"There are some errors in the form you posted."
)
vforms
=
instances
vforms
=
instances
else
:
if
Choice
.
objects
.
filter
(
poll
=
poll_id
).
count
()
==
0
:
...
...
@@ -136,7 +129,7 @@ def editchoices(request, poll_id):
@
login_required
def
delete
(
request
,
poll_id
):
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
if
poll
.
author
==
str
(
request
.
user
):
poll
.
delete
()
...
...
@@ -151,12 +144,12 @@ def make_buletin_form(poll, **kwargs):
def
vote
(
request
,
poll_id
):
error_message
=
None
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
has_voted
=
False
if
request
.
method
==
'POST'
:
form
=
BulletinForm
(
request
.
POST
,
initial
=
{
'poll'
:
poll
.
id
,})
form
=
BulletinForm
(
request
.
POST
,
initial
=
{
'poll'
:
poll
.
id
,})
vforms
=
[
[
VoteForm
(
request
.
POST
,
prefix
=
choice
,
instance
=
choice
)
]
for
choice
in
Choice
.
objects
.
filter
(
poll
=
poll
.
id
)
]
if
form
.
is_valid
():
...
...
@@ -177,22 +170,22 @@ def vote(request, poll_id):
pass
"""
if
not
Bulletin
.
objects
.
filter
(
poll
=
poll
.
id
,
voter
=
voter
):
bulletin
=
Bulletin
(
poll
=
poll
,
voter
=
voter
)
if
not
Bulletin
.
objects
.
filter
(
poll
=
poll
.
id
,
voter
=
voter
):
bulletin
=
Bulletin
(
poll
=
poll
,
voter
=
voter
)
bulletin
.
save
()
else
:
bulletin
=
Bulletin
.
objects
.
get
(
poll
=
poll
.
id
,
voter
=
voter
)
bulletin
=
Bulletin
.
objects
.
get
(
poll
=
poll
.
id
,
voter
=
voter
)
for
forms
in
vforms
:
for
vorm
in
forms
:
if
vorm
.
is_valid
():
try
:
choice
=
Choice
.
objects
.
get
(
choice
=
vorm
.
cleaned_data
[
'choice'
],
poll
=
poll
)
choice
=
Choice
.
objects
.
get
(
choice
=
vorm
.
cleaned_data
[
'choice'
],
poll
=
poll
)
except
:
return
HttpResponse
(
vorm
.
cleaned_data
[
'choice'
])
if
not
Vote
.
objects
.
filter
(
choice
=
choice
,
bulletin
=
bulletin
):
new
=
Vote
(
choice
=
choice
,
bulletin
=
bulletin
,
comment
=
vorm
.
cleaned_data
[
'comment'
])
if
not
Vote
.
objects
.
filter
(
choice
=
choice
,
bulletin
=
bulletin
):
new
=
Vote
(
choice
=
choice
,
bulletin
=
bulletin
,
comment
=
vorm
.
cleaned_data
[
'comment'
])
if
vorm
.
cleaned_data
[
'voice'
]:
new
.
voice
=
vorm
.
cleaned_data
[
'voice'
]
new
.
save
()
...
...
@@ -206,7 +199,7 @@ def vote(request, poll_id):
request
.
session
[
'name'
]
=
voter
# This writes cookie
has_voted
=
True
# Used to show "Forget me"
else
:
old
=
Vote
.
objects
.
get
(
choice
=
choice
,
bulletin
=
bulletin
)
old
=
Vote
.
objects
.
get
(
choice
=
choice
,
bulletin
=
bulletin
)
if
old
.
voice
:
if
not
vorm
.
cleaned_data
[
'voice'
]:
...
...
@@ -255,7 +248,7 @@ def vote(request, poll_id):
we should concatenate the existing votes with empty remaing ones...
Give an empty bulletin for now.
"""
vforms
=
[
[
VoteForm
(
initial
=
{
'choice'
:
vote
.
choice
,
'voice'
:
vote
.
voice
,
'comment'
:
vote
.
comment
,
},
prefix
=
vote
.
choice
)
]
for
vote
in
Vote
.
objects
.
filter
(
bulletin
=
bulletin
).
order_by
(
'choice__choice'
)
]
vforms
=
[
[
VoteForm
(
initial
=
{
'choice'
:
vote
.
choice
,
'voice'
:
vote
.
voice
,
'comment'
:
vote
.
comment
},
prefix
=
vote
.
choice
)
]
for
vote
in
Vote
.
objects
.
filter
(
bulletin
=
bulletin
).
order_by
(
'choice__choice'
)
]
except
:
pass
...
...
@@ -268,7 +261,7 @@ def vote(request, poll_id):
voter
=
request
.
session
.
get
(
'name'
)
#error_message = 'Modify your vote? (clear cookie if you are not ' + voter + ')'
try
:
bulletin
=
Bulletin
.
objects
.
get
(
poll
=
poll
,
voter
=
voter
)
bulletin
=
Bulletin
.
objects
.
get
(
poll
=
poll
,
voter
=
voter
)
error_message
=
voter
+
' has voted'
diff
=
len
(
vforms
)
-
len
(
Vote
.
objects
.
filter
(
bulletin
=
bulletin
))
if
diff
==
0
:
...
...
@@ -294,13 +287,13 @@ def exp_csv(request, poll_id):
response
=
HttpResponse
(
mimetype
=
'text/csv'
)
response
[
'Content-Disposition'
]
=
'attachment; filename=nuages.csv'
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
poll
=
get_object_or_404
(
Poll
.
objects
.
all
(),
id
=
poll_id
)
choices
=
Choice
.
objects
.
filter
(
poll
=
poll
)
bulletins
=
Bulletin
.
objects
.
filter
(
poll
=
poll
)
writer
=
csv
.
writer
(
response
,
quotechar
=
'"'
,
quoting
=
csv
.
QUOTE_ALL
)
fr
=
[
""
,]
for
c
in
choices
:
fr
.
append
(
c
)
fr
.
append
(
c
)
writer
.
writerow
(
fr
)
for
b
in
bulletins
:
r
=
[
b
.
voter
.
encode
(
"utf-8"
),]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment