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, PattUserProfileForm from .help import help_pages from .models import Task, ModelList, Comment, TASKSTATE_CHOICES, PRIO_CHOICES, TASKS_IN_WORK from .models import Project, Search, get_pattuserprofile import patt from .search import load_index, search, mk_search_pattern, get_project_ids_from_search_pattern, common_searches from users.forms import UserProfileForm from users.models import get_userprofile 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', '/') def profile_post_actions(request, context): if request.POST: form = context.get('form_userprofile') if form.is_valid(): form.save() form = context.get('form_pattprofile') if form.is_valid(): form.save() return redirect(request.GET.get('next') or '/') def profile_pre_actions(request, context, form_to_be_used=UserProfileForm): user_profile = get_userprofile(request.user) patt_user_profile = get_pattuserprofile(request.user) if request.POST: userprofile_form = UserProfileForm(request.POST, instance=user_profile) pattprofile_form = PattUserProfileForm(request.POST, instance=patt_user_profile) else: userprofile_form = UserProfileForm(instance=user_profile) pattprofile_form = PattUserProfileForm(instance=patt_user_profile) context['form_userprofile'] = userprofile_form context['form_pattprofile'] = pattprofile_form @login_required def patt_profile(request): context = Context(request) # needs to be executed first because of time mesurement profile_pre_actions(request, context) response = profile_post_actions(request, context) if response is not None: return response else: context_adaption(context, request, title=_('Profile for %(username)s') % {'username': request.user.username}) return render(request, 'patt/profile.html', context=context) @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)