patt/views.py

691 rinda
36 KiB
Python

from .access import acc_task, acc_project, create_project_possible, create_task_possible
from .context import context_adaption
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import User
from django.shortcuts import render, redirect
from django.urls.base import reverse
from django.utils import timezone
from django.utils.translation import gettext as _
from .forms import TaskForm, TaskFormLimited, ProjectForm, CommentForm, TaskCommentForm, SearchForm, EasySearchForm
from .help import help_pages
from .models import Task, ModelList, Comment, TASKSTATE_CHOICES, PRIO_CHOICES, TASKS_IN_WORK
from .models import Project, Search
import patt
from .search import load_index, search, mk_search_pattern, get_project_ids_from_search_pattern, common_searches
from themes import Context
class Like(object):
DATA = []
def __init__(self, request, obj):
for key in self.DATA:
if key in request.POST:
setattr(self, key, request.POST.get(key))
else:
try:
setattr(self, key, getattr(obj, key))
except AttributeError:
setattr(self, key, None)
self.__init_additions__(request, obj)
if self.creation_date is None:
self.creation_date = timezone.now()
if self.id is None:
self.id = 'xxx'
def __init_additions__(self, request, obj):
pass
class TaskLike(Like):
DATA = ['id', 'state', 'priority', 'targetdate', 'progress', 'name', 'description', 'creation_date', 'comments']
def __init_additions__(self, request, obj):
if 'project' in request.POST:
self.project = Project.objects.get(id=request.POST.get('project'))
else:
self.project = getattr(obj, 'project')
if 'assigned_user' in request.POST:
try:
self.assigned_user = User.objects.get(id=request.POST.get('assigned_user'))
except ValueError:
self.assigned_user = None
else:
self.assigned_user = getattr(obj, 'assigned_user')
#
self.class_by_state = 'task-normal' if self.state == '0' else 'task-finished'
#
if obj is None:
self.attachment_target_path = Task().attachment_target_path
else:
self.attachment_target_path = obj.attachment_target_path
if self.assigned_user and self.id:
self.taskname_prefix = '**#%d //(%s)//:** ' % (self.id, self.assigned_user.username)
elif self.id:
self.taskname_prefix = '**#%d:** ' % self.id
elif self.assigned_user:
self.taskname_prefix = '**//(%s)//:** ' % self.assigned_user.username
else:
self.taskname_prefix = ''
class CommentLike(Like):
DATA = ['id', 'type', 'creation_date', 'comment']
def __init_additions__(self, request, obj):
if 'user' in request.POST:
self.user = User.objects.get(id=request.POST.get('user'))
else:
try:
self.user = getattr(obj, 'user')
except AttributeError:
self.user = request.user
#
if obj is None:
self.attachment_target_path = Comment().attachment_target_path
else:
self.attachment_target_path = obj.attachment_target_path
class ProjectLike(Like):
DATA = ['id', 'name', 'description', 'state', 'creation_date']
def __init_additions__(self, request, obj):
self.role_leader = [User.objects.get(id=user_id) for user_id in request.POST.getlist('role_leader', [])]
self.role_member = [User.objects.get(id=user_id) for user_id in request.POST.getlist('role_member', [])]
self.creation_date = '-'
self.formatted_leaders = ', '.join([user.username for user in self.role_leader])
self.formatted_members = ', '.join([user.username for user in self.role_member])
#
if obj is None:
self.attachment_target_path = Project().attachment_target_path
else:
self.attachment_target_path = obj.attachment_target_path
def permission_denied_msg_project(request, project_id):
if project_id is None:
messages.error(request, _('Permission denied to create a new Project.'))
else:
messages.error(request, _('Permission denied to Project #%(project_id)d') % {'project_id': project_id})
def permission_denied_msg_task(request, task_id):
if task_id is None:
messages.error(request, _('Permission denied to create a new Task'))
else:
messages.error(request, _('Permission denied to Task #%(task_id)d') % {'task_id': task_id})
def permission_denied_msg_comment(request, task_id):
messages.error(request, _('Permission denied to add or edit a comment of Task #%(task_id)d') % {'task_id': task_id})
def no_change_msg(request):
messages.info(request, _("Nothing changed, no storage needed."))
def does_not_exist_msg_task(request, task_id):
messages.error(request, _('Task #%(id)d does not exist!') % {'id': task_id})
def does_not_exist_msg_search(request, search_id):
messages.error(request, _('Search #%(id)d does not exist!') % {'id': search_id})
def get_next(request):
if not request.POST:
return request.GET.get('next', '/')
else:
return request.POST.get('next', '/')
@login_required
def patt_tasklist(request, user_filter_id=None, common_filter_id=None):
context = Context(request) # needs to be executed first because of time mesurement
is_printview = patt.is_printview(request)
search_txt = patt.get_search_query(request)
if user_filter_id is not None:
try:
s = Search.objects.get(id=user_filter_id)
except Search.DoesNotExist:
does_not_exist_msg_search(request, user_filter_id)
return redirect(patt.url_tasklist(request))
search_txt = s.search_txt
title = s.name
ix = load_index()
sr = search(ix, search_txt)
if sr is None:
messages.error(request, _('Invalid search pattern: %s') % repr(search_txt))
sr = []
tasklist = ModelList(sr, acc_task, request.user)
elif search_txt is not None:
ix = load_index()
sr = search(ix, search_txt)
if sr is None:
messages.error(request, _('Invalid search pattern: %s') % repr(search_txt))
sr = []
tasklist = ModelList(sr, acc_task, request.user)
max_len = 25
if len(search_txt) > max_len:
title = _('Searchresults for %s') % repr(search_txt[:max_len - 3] + '...')
else:
title = _('Searchresults for %s') % repr(search_txt)
elif common_filter_id is not None:
try:
title, search_txt = common_searches(request)[common_filter_id]
except KeyError:
messages.error(request, _('Invalid common search: %s') % repr(common_filter_id))
sr = []
title = _('Common Search Error')
else:
ix = load_index()
sr = search(ix, search_txt)
if sr is None:
messages.error(request, _('Invalid search pattern: %s') % repr(search_txt))
sr = []
tasklist = ModelList(sr, acc_task, request.user)
else:
tasklist = ModelList(Task.objects.filter(state__in=TASKS_IN_WORK), acc_task, request.user)
title = _("All Tasks in work")
try:
project_id = get_project_ids_from_search_pattern(search_txt)[0]
except IndexError:
project_id = None
except TypeError:
project_id = None
tasklist.sort()
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
tasklist=tasklist, # the tasklist to be shown (template)
printview=is_printview, # Show reduced view and functionality in printview
target_head=None if is_printview else 'patt-taskview', # target-link for head (template)
project_id=project_id, # as default Value for New Task entry
title=title, # the title for the page (template)
)
if patt.is_printview(request):
return render(request, 'patt/tasklist_print.html', context=context)
else:
return render(request, 'patt/tasklist.html', context=context)
@login_required
def patt_projectlist(request):
context = Context(request) # needs to be executed first because of time mesurement
projectlist = ModelList(Project.objects.all(), acc_project, request.user)
projectlist.sort()
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
projectlist=projectlist, # the projectlist to be shown (template)
target_head='patt-projectedit', # target-link for head (template)
title=_("Projectlist"), # the title for the page (template)
)
return render(request, 'patt/projectlist.html', context=context)
@login_required
def patt_taskview(request, task_id):
context = Context(request) # needs to be executed first because of time mesurement
is_printview = patt.is_printview(request)
try:
task = Task.objects.get(id=task_id)
except Task.DoesNotExist:
does_not_exist_msg_task(request, task_id)
else:
acc = acc_task(task, request.user)
if acc.read:
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
task=task, # the task to be shown (template)
printview=is_printview, # Show reduced view and functionality in printview
taskview=True, # deactivate collapse and expand buttons
target_head=None if is_printview else 'patt-taskedit', # target-link for head (template)
project_id=task.project.id, # as default Value for New Task entry
title=_('Task #%d') % task.id # the title for the page (template)
)
if patt.is_printview(request):
return render(request, 'patt/taskview_print.html', context=context)
else:
return render(request, 'patt/taskview.html', context=context)
else:
permission_denied_msg_task(request, task.id)
return redirect(reverse('patt-tasklist'))
@login_required
def patt_tasknew(request):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
if create_task_possible(request.user):
if not request.POST: # Initial Form...
task = Task(project_id=request.GET.get('project_id'))
form = TaskForm(instance=task, request=request)
form_comment = TaskCommentForm()
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the task form (template)
form_comment=form_comment, # the form object to create the comment form (template)
next=nxt, # the url for redirection
title=_('New Task') # the title for the page (template)
)
return render(request, 'patt/task_form.html', context=context)
else:
task = Task()
form = TaskForm(request.POST, instance=task, request=request)
form_comment = TaskCommentForm(request.POST)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the task form (template)
form_comment=form_comment, # the form object to create the comment form (template)
next=nxt, # the url for redirection
title=_('New Task') # the title for the page (template)
)
if request.POST.get('save'): # Save form content...
if form.is_valid() and form_comment.is_valid():
form.save()
if request.POST.get('comment'):
form_comment = TaskCommentForm(request.POST, instance=Comment(task_id=form.instance.id, user=request.user))
form_comment.save()
messages.success(request, _('Thanks for adding Task #%(task_id)d.') % {'task_id': form.instance.id})
return redirect(nxt + '#task-%d' % form.instance.id)
elif request.POST.get('preview'): # Create a preview
context['comment_new'] = CommentLike(request, None) # the new comment to be used in the preview
context['template'] = 'patt/task/task.html' # the template for preview (template)
context['task'] = TaskLike(request, task) # the object to be used in the preview template
context['printview'] = True # Show reduced view and functionality like in printview
return render(request, 'patt/task_form.html', context=context)
else:
permission_denied_msg_task(request, None)
return redirect(nxt)
@login_required
def patt_projectnew(request):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
if create_project_possible(request.user):
project = Project()
if not request.POST:
form = ProjectForm(instance=project)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('New Project') # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
form = ProjectForm(request.POST, instance=project)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('New Project') # the title for the page (template)
)
#
if request.POST.get('save'):
if form.is_valid():
form.save()
messages.success(request, _('Thanks for adding Project #%(project_id)d.') % {'project_id': form.instance.id})
return redirect(nxt + '#project-%d' % form.instance.id)
elif request.POST.get('preview'):
context['template'] = 'patt/project/project.html' # the template for preview (template)
context['project'] = ProjectLike(request, None) # the object to be used in the preview template
return render(request, 'patt/raw_single_form.html', context=context)
else:
permission_denied_msg_project(request, None)
return redirect(nxt)
@login_required
def patt_taskedit(request, task_id, **kwargs):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
try:
task = Task.objects.get(id=task_id)
except Task.DoesNotExist:
does_not_exist_msg_task(request, task_id)
return redirect(nxt)
else:
acc = acc_task(task, request.user)
if acc.modify or acc.modify_limited:
if acc.modify:
ThisForm = TaskForm
else:
ThisForm = TaskFormLimited
if not request.POST:
# get request parameters
do = request.GET.get('do')
state = request.GET.get('state')
if state:
state = int(state)
priority = request.GET.get('priority')
if priority:
priority = int(priority)
#
if do == 'edit':
form = ThisForm(instance=task, request=request)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the task form (template)
form_comment=TaskCommentForm(), # the form object to create the comment form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task.id, # the anchor for redirection
title=_('Edit Task #%d') % task.id # the title for the page (template)
)
return render(request, 'patt/task_form.html', context=context)
elif do == 'set_state':
if state in acc.allowed_targetstates:
task.state = state
task.save()
messages.success(request, _('State of Task #%(task_id)d set to %(name)s') % {'task_id': task.id, 'name': dict(TASKSTATE_CHOICES)[state]})
else:
permission_denied_msg_task(request, task_id)
elif do == 'set_priority':
if priority in acc.allowed_targetpriority:
task.priority = priority
task.save()
messages.success(request, _('Priority of Task #%(task_id)d set to %(name)s') % {'task_id': task.id, 'name': dict(PRIO_CHOICES)[priority]})
else:
permission_denied_msg_task(request, task_id)
else:
messages.error(request, 'Edit with do="%s" not yet implemented!' % do)
return redirect(nxt + '#task-%d' % task_id)
else:
comment = Comment(task_id=task_id, user=request.user)
form = ThisForm(request.POST, instance=task, request=request)
form_comment = TaskCommentForm(request.POST, instance=comment)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the task form (template)
form_comment=form_comment, # the form object to create the comment form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task.id, # the anchor for redirection
title=_('Edit Task #%d') % task.id # the title for the page (template)
)
if request.POST.get('save'):
if form.is_valid() and form_comment.is_valid(): # TODO: Validator depending on modify and modify_limited (to ensure content is okay for this user)!
save_needed = form.save().save_needed
if request.POST.get('comment'):
save_needed |= form_comment.save().save_needed
if save_needed:
messages.success(request, _('Thanks for editing Task #%(task_id)d.') % {'task_id': task.id})
else:
no_change_msg(request)
return redirect(nxt + '#task-%d' % task_id)
elif request.POST.get('preview'):
context['comment_new'] = CommentLike(request, comment) # the new comment to be used in the preview
context['template'] = 'patt/task/task.html' # the template for preview (template)
context['task'] = TaskLike(request, task) # the object to be used in the preview template
context['printview'] = True # Show reduced view and functionality like in printview
return render(request, 'patt/task_form.html', context=context)
else:
permission_denied_msg_task(request, task_id)
return redirect(nxt + '#task-%d' % task_id)
@login_required
def patt_projectedit(request, project_id):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
try:
project = Project.objects.get(id=project_id)
except Task.DoesNotExist:
messages.error(request, _('Project with id %(project_id)d does not exist!') % {'project_id': project_id})
return redirect(nxt)
else:
acc = acc_project(project, request.user)
if acc.modify:
if not request.POST:
form = ProjectForm(instance=project)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='project-%d' % project_id, # the anchor for redirection
item_id=project.id, # project.id for Preview, ... (template)
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Edit Project #%d') % project_id # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
form = ProjectForm(request.POST, instance=project)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='project-%d' % project_id, # the anchor for redirection
item_id=project.id, # project.id for Preview, ... (template)
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Edit Project #%d') % project_id # the title for the page (template)
)
#
if request.POST.get('save'):
if form.is_valid():
form.save()
messages.success(request, _('Thanks for editing Project #%(project_id)d.') % {'project_id': project.id})
return redirect(nxt + '#project-%d' % project_id)
elif request.POST.get('preview'):
context['template'] = 'patt/project/project.html' # the template for preview (template)
context['project'] = ProjectLike(request, project) # the object to be used in the preview template
return render(request, 'patt/raw_single_form.html', context=context)
else:
permission_denied_msg_project(request, project_id)
return redirect(nxt + '#project-%d' % project_id)
@login_required
def patt_commentnew(request, task_id):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
try:
task = Task.objects.get(id=task_id)
except Task.DoesNotExist:
does_not_exist_msg_task(request, task_id)
return redirect(nxt)
else:
acc = acc_task(task, request.user)
if acc.add_comments:
if not request.POST:
form = CommentForm(instance=Comment(), acc=acc)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task_id, # the anchor for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Add a Comment (Task #%d)') % task_id # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
comment = Comment(task_id=task_id, user=request.user)
#
form = CommentForm(request.POST, instance=comment, acc=acc)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task_id, # the anchor for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Add Comment to Task #%d') % task_id # the title for the page (template)
)
if request.POST.get('save'):
if form.is_valid():
form.save()
messages.success(request, _('Thanks for adding a comment to Task #%(task_id)d.') % {'task_id': task_id})
return redirect(nxt + '#task-%d' % task_id)
elif request.POST.get('preview'):
context['template'] = 'patt/task/comment.html' # the template for preview (template)
context['comment'] = CommentLike(request, comment) # the object to be used in the preview template
return render(request, 'patt/raw_single_form.html', context=context)
else:
permission_denied_msg_comment(request, task_id)
return redirect(nxt + '#task-%d' % task_id)
@login_required
def patt_commentedit(request, task_id, comment_id):
context = Context(request) # needs to be executed first because of time mesurement
nxt = get_next(request)
comment = Comment.objects.get(id=comment_id)
acc = acc_task(comment.task, request.user)
if acc.modify_comment:
if not request.POST:
form = CommentForm(instance=comment, acc=acc)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task_id, # the anchor for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Edit Comment (Task #%d)') % task_id # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
form = CommentForm(request.POST, instance=comment, acc=acc)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
next=nxt, # the url for redirection
next_anchor='task-%d' % task_id, # the anchor for redirection
disable_delete=True, # disable delete button
disable_search=True, # disable search button
title=_('Edit Comment (Task #%d)') % task_id # the title for the page (template)
)
#
if request.POST.get('save'):
if form.is_valid():
if form.save().save_needed:
messages.success(request, _('Thanks for editing a comment of Task #%(task_id)d.') % {'task_id': task_id})
else:
no_change_msg(request)
return redirect(nxt + '#task-%d' % task_id)
elif request.POST.get('preview'):
context['template'] = 'patt/task/comment.html' # the template for preview (template)
context['comment'] = CommentLike(request, comment) # the object to be used in the preview template
return render(request, 'patt/raw_single_form.html', context=context)
else:
permission_denied_msg_comment(request, task_id)
return redirect(nxt + '#task-%d' % task_id)
def patt_filteredit(request, search_id=None):
def filter_does_not_exist_error(request, search_id):
messages.error(request, _('Filter #%d does not exist.') % search_id)
context = Context(request) # needs to be executed first because of time mesurement
if not request.POST:
if search_id is not None:
try:
form = SearchForm(instance=Search.objects.get(id=search_id))
except Search.DoesNotExist:
filter_does_not_exist_error(request, search_id)
return redirect('/')
else:
if patt.get_search_query(request) is None:
form = SearchForm(initial={'user': request.user})
else:
form = SearchForm(initial={'search_txt': patt.get_search_query(request), 'user': request.user})
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
disable_preview=True, # disable the preview button
disable_search=True, # disable search button
title=_('Edit Filter') # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
if search_id is not None:
try:
s = Search.objects.get(id=search_id)
except Search.DoesNotExist:
filter_does_not_exist_error(request, search_id)
return redirect('/')
else:
s = Search(user=request.user)
if request.user == s.user:
form = SearchForm(request.POST, instance=s)
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
disable_preview=True, # disable the preview button
disable_search=True, # disable search button
title=_('Edit Filter') # the title for the page (template)
)
#
if request.POST.get('save'):
if form.is_valid():
s.save()
messages.success(request, _('Thanks for editing Filter #%(search_id)d.') % {'search_id': s.id})
return redirect(patt.url_tasklist(request, user_filter_id=s.id))
elif request.POST.get('delete'):
messages.success(request, _('Filter #%(search_id)d delteted.') % {'search_id': s.id})
s.delete()
return redirect('/')
return render(request, 'patt/raw_single_form.html', context=context)
else:
messages.error(request, _('Access to Filter (%s) denied.') % repr(search_id))
return redirect('/')
def patt_easysearch(request):
context = Context(request) # needs to be executed first because of time mesurement
if not request.POST:
form = EasySearchForm()
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
form=form, # the form object to create the form (template)
disable_preview=True, # disable the preview button
disable_delete=True, # disable the delete button
disable_save=True, # disable save button
title=_('Edit Filter') # the title for the page (template)
)
return render(request, 'patt/raw_single_form.html', context=context)
else:
form = EasySearchForm(request.POST)
form_data = dict(form.data)
if 'states' not in form_data:
form_data['states'] = []
return redirect(patt.url_tasklist(request, search_txt=mk_search_pattern(**form_data)))
def patt_helpview(request, page='main'):
context = Context(request) # needs to be executed first because of time mesurement
help_content = help_pages[page]
context_adaption(
context, # the base context
request, # the request object to be used in context_adaption
current_help_page=page, # the current help_page to identify which taskbar entry has to be highlighted
help_content=help_content, # the help content itself (template)
title=_('Help') # the title for the page (template)
)
return render(request, 'patt/help.html', context=context)