diff --git a/media/css/main.css b/media/css/main.css
index 0bdd163..8b1d639 100644
--- a/media/css/main.css
+++ b/media/css/main.css
@@ -306,6 +306,23 @@ span.pager {
background: #cfc;
}
+.task {
+ border: 1px #ddd solid;
+ padding: 1ex;
+}
+
+.task-state-0 {
+ background: #fee;
+}
+
+.task-state-1 {
+ background: #ffd;
+}
+
+.task-state-2 {
+ background: #dfd;
+}
+
.git-tags {
border-left: 1px #888 solid;
float: right;
diff --git a/mgmt/decorators.py b/mgmt/decorators.py
index 845d544..5b49597 100644
--- a/mgmt/decorators.py
+++ b/mgmt/decorators.py
@@ -1,6 +1,15 @@
-from django.http import HttpResponseForbidden
+from django.http import HttpResponseForbidden,HttpResponseRedirect
from rights import can
+def login_required(func):
+ def wrapper(request,*args,**kwargs):
+ if request.user.is_authenticated():
+ return func(request,*args,**kwargs)
+ else:
+ return HttpResponseRedirect('/login/')
+ wrapper.__name__ = func.__name__
+ return wrapper
+
####################
# User auth tests
####################
diff --git a/mgmt/forms.py b/mgmt/forms.py
index 04c335e..ba7c1f3 100644
--- a/mgmt/forms.py
+++ b/mgmt/forms.py
@@ -49,3 +49,6 @@ class TaskModelForm(forms.ModelForm):
model = Task
exclude = ("created","author","status","project")
+class TaskStateForm(forms.Form):
+ state = forms.ChoiceField(settings.TASK_STATES)
+
diff --git a/mgmt/rights.py b/mgmt/rights.py
index 8705bea..3161be8 100644
--- a/mgmt/rights.py
+++ b/mgmt/rights.py
@@ -37,22 +37,25 @@ def can(user,action,object=None,target=None):
if action == 'create task':
return user in object.admins.iterator()
+ if action == 'change_state':
+ if cls == 'Bug':
+ return can_change_bug_state(user,object,target)
+ if cls == 'Request':
+ return user in object.project.admins.iterator()
+ if cls == 'Task':
+ return user.id in [object.to.id, object.author.id] or user.is_staff
+
if cls == 'PrivateMsg':
if action == 'delete':
return user.id == object.reciever.id
if cls == 'Comment':
if action == 'delete':
return user.id == object.author.id or user.is_staff
- if cls == 'Request':
- if action == 'change_state':
- return user in object.project.admins.iterator()
if cls == 'Bug':
if action == 'set_priority':
return user in object.project.admins.iterator() and not object.status.id in [1,4,5]
if action == 'set_complexity':
return user in object.project.team.iterator() and not object.status.id in [1,4,5]
- if action == 'change_state':
- return can_change_bug_state(user,object,target)
return False
def possible_changes(bug,user):
diff --git a/mgmt/views.py b/mgmt/views.py
index 2f386eb..27da8ed 100644
--- a/mgmt/views.py
+++ b/mgmt/views.py
@@ -6,7 +6,6 @@ from datetime import datetime
from django.http import HttpResponse,Http404,HttpResponseForbidden,HttpResponseRedirect
import django.newforms as djangoforms
from django.contrib.auth.models import User
-from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.conf import settings
@@ -16,7 +15,7 @@ from models import *
from rights import can,possible_changes
from utils import *
from forms import *
-from decorators import check_auth
+from decorators import check_auth,login_required
#############
# Views
@@ -45,6 +44,8 @@ def one_project(request,id):
form = CommentForm()
else:
form = None
+ for comment in comments:
+ comment.can_delete = can(request.user,'delete',comment)
return render_it('project.html',
{'project': project,
'current_page': curr,
@@ -135,6 +136,8 @@ def one_document(request,id):
edit_link = '/docs/%s/edit/' % id
else:
edit_link = None
+ for comment in comments:
+ comment.can_delete = can(request.user,'delete',comment)
return render_it('document.html',
{'document': doc,
'edit_link': edit_link,
@@ -216,6 +219,8 @@ def one_bug(request,id):
edit_link = '/bugs/%s/edit/' % bug.id
else:
edit_link = None
+ for comment in comments:
+ comment.can_delete = can(request.user,'delete',comment)
priority = dict(settings.PRIORITY_CHOICES).get(bug.priority,u'Unset')
complexity = dict(settings.COMPLEXITY_CHOICES).get(bug.complexity,'Unknown')
return render_it('bug.html',
@@ -326,7 +331,7 @@ def user_page(request,name):
pr_team = Project.objects.filter(team=user)
bugs_resp = Bug.objects.filter(responsible=user,status__id__lt=4)
- tasks = user.task_set.select_related().all()
+ tasks = user.task_set.select_related().filter(status__lt=2)
return render_it('user_page.html',
{'user_view': user,
@@ -353,9 +358,17 @@ def project_tasks(request,pid):
def one_task(request,tid):
task = Task.objects.select_related().get(pk=tid)
+ if request.method=='POST':
+ task.status = request.POST['state']
+ task.save()
can_edit = can(request.user,'edit',task)
+ if can(request.user,'change_state',task):
+ state_form = TaskStateForm({'state': task.status})
+ else:
+ state_form = None
return render_it('task.html',
{'task': task,
+ 'state_form': state_form,
'can_edit': can_edit},
request)
diff --git a/templates/comments.html b/templates/comments.html
index 3aeddc5..6a8c58b 100644
--- a/templates/comments.html
+++ b/templates/comments.html
@@ -5,9 +5,11 @@
{% for comment in comments %}
<div class='comment'>
<div class='comment-title'>
+ {% if comment.can_delete %}
<div class='links'>
<a href='{% url mgmt.views.delete_comment comment.id %}'>Удалить</a>
</div>
+ {% endif %}
<a name='comment-{{comment.id}}'>#</a>
{{comment.title}} от <a href='{% url mgmt.views.user_page comment.author %}'>{{comment.author}}</a>, {{comment.created}}
</div>
diff --git a/templates/registration/login.html b/templates/registration/login.html
index 9973bfa..c8b953c 100644
--- a/templates/registration/login.html
+++ b/templates/registration/login.html
@@ -11,7 +11,7 @@
<form action='/login/' method='post'>
<p><label for="username">Логин:</label><input type="text" name="username" value="" id="username"/></p>
<p><label for="password">Пароль:</label><input type="password" name="password" value="" id="password"/></p>
- <input type='hidden' name='next' value='{{next}}'/>
+ <input type='hidden' name='next' value='/'/>
<input type="submit" value="login" />
</form>
{% endblock %}
diff --git a/templates/task.html b/templates/task.html
index 3dae315..929e177 100644
--- a/templates/task.html
+++ b/templates/task.html
@@ -11,17 +11,23 @@
{% endif %}
<h2>Задание: {{task.name}}</h2>
-<p><strong>Автор:</strong> <a href='{% url mgmt.views.user_page task.author.username %}'>{{task.author.username}}</a></p>
-<p><strong>Кому:</strong> <a href='{% url mgmt.views.user_page task.to.username %}'>{{task.to.username}}</a></p>
-
-{% if task.bug %}
-<p><strong>Связанный баг:</strong> <a href='{% url mgmt.views.one_bug task.bug.id %}'>{{task.bug.name}}</a></p>
-{% endif %}
+<div class='task task-state-{{task.status}}'>
+ <p><strong>Автор:</strong> <a href='{% url mgmt.views.user_page task.author.username %}'>{{task.author.username}}</a></p>
+ <p><strong>Кому:</strong> <a href='{% url mgmt.views.user_page task.to.username %}'>{{task.to.username}}</a></p>
+
+ {% if task.bug %}
+ <p><strong>Связанный баг:</strong> <a href='{% url mgmt.views.one_bug task.bug.id %}'>{{task.bug.name}}</a></p>
+ {% endif %}
+
+ {% if task.request %}
+ <p><strong>Связанный запрос функциональности:</strong> <a href='{% url mgmt.views.one_request task.request.id %}'>{{task.request.name}}</a></p>
+ {% endif %}
+
+ {{task.text|markdown|safe}}
+</div>
-{% if task.request %}
-<p><strong>Связанный запрос функциональности:</strong> <a href='{% url mgmt.views.one_request task.request.id %}'>{{task.request.name}}</a></p>
+{% if state_form %}
+ {% form state_form %}
{% endif %}
-
-{{task.text|markdown|safe}}
-
+
{% endblock %}
diff --git a/templates/tasks_table.html b/templates/tasks_table.html
index bf864c5..7117636 100644
--- a/templates/tasks_table.html
+++ b/templates/tasks_table.html
@@ -1,7 +1,7 @@
{% load prj_filters %}
<table>
{% for task in tasks %}
- <tr>
+ <tr class='task task-state-{{task.status}}'>
<td><a href='{% url mgmt.views.one_project task.project.id %}'>{{task.project.name}}</a></td>
<td><a href='{% url mgmt.views.one_task task.id %}'>{{task.name}}</a></td>
<td><a href='{% url mgmt.views.user_page task.author.username %}'>{{task.author.username}}</a></td>