def new(request, board_id): member = request.user.member board = get_user_board_or_404(request.user, board_id) requirement = Requirement(board=board) if request.method == "POST": form = NewRequirementForm(request.POST, instance=requirement) if form.is_valid(): form.save(commit=True) return HttpResponseRedirect( reverse("boards:requirements:view_requirements", args=(board_id, ))) else: form = NewRequirementForm(instance=requirement) return render(request, "requirements/new.html", { "form": form, "board": board, "member": member })
def delete(request, board_id): member = request.user.member # Load the board board = get_user_board_or_404(request.user, board_id) # Show delete form if request.method == "GET": replacements = {"member": member, "board": board} return render(request, "boards/delete.html", replacements) # Delete action by post confirmed_board_id = request.POST.get("board_id") if confirmed_board_id and confirmed_board_id == board_id: # Only archived boards can be deleted if board.is_archived: board.delete() return HttpResponseRedirect(reverse("boards:view_boards")) else: replacements = {"member": member, "board": board} return render(request, "boards/delete.html", replacements) raise Http404
def view_identicon(request, board_id, width=40, height=40): board = get_user_board_or_404(request.user, board_id, is_archived=None) # List of colors taken from example http://pydenticon.readthedocs.io/en/0.3/usage.html#instantiating-a-generator foreground = [ "#{0}".format(board.title_color), "rgb(45,79,255)", "rgb(254,180,44)", "rgb(226,121,234)", "rgb(30,179,253)", "rgb(232,77,65)", "rgb(49,203,115)", "rgb(141,69,170)" ] # Background color taken from example http://pydenticon.readthedocs.io/en/0.3/usage.html#instantiating-a-generator background = u"#{0}".format(board.background_color) identicon_hash = hashlib.sha1(board.name.encode('utf-8')).hexdigest() # If the identicon is already stored, return it if identicon_hash == board.identicon_hash: return HttpResponseRedirect(board.identicon.url) # Otherwise, its generation is needed board.identicon_hash = identicon_hash generator = pydenticon.Generator(5, 5, digest=hashlib.sha1, foreground=foreground, background=background) identicon_png = generator.generate(board.name, int(width), int(height), output_format="png") board.identicon.save(u"{0}".format(identicon_hash), ContentFile(identicon_png)) board.save() return HttpResponseRedirect(board.identicon.url)
def export_report(request, board_id): member = None if user_is_member(request.user): member = request.user.member board = get_user_board_or_404(request.user, board_id) cards = board.cards.all() response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = u'attachment; filename="{0}-cards.csv"'.format(board.name) csv_template = loader.get_template('boards/cards/csv.txt') replacements = { "member": member, "board": board, "cards": cards, "avg_lead_time": avg(cards, "lead_time"), "std_dev_lead_time": std_dev(cards, "lead_time"), "avg_cycle_time": avg(cards, "cycle_time"), "std_dev_cycle_time": std_dev(cards, "cycle_time"), } response.write(csv_template.render(replacements)) return response
def view_workflow_card_report(request, board_id, workflow_id): member = None if user_is_member(request.user): member = request.user.member board = get_user_board_or_404(request.user, board_id) workflow = board.workflows.get(id=workflow_id) workflow_card_reports = board.workflow_card_reports.filter( workflow_id=workflow_id) replacements = { "workflow": workflow, "member": member, "board": board, "workflow_card_reports": workflow_card_reports, "avg_lead_time": avg(workflow_card_reports, "lead_time"), "std_dev_lead_time": std_dev(workflow_card_reports, "lead_time"), "avg_cycle_time": avg(workflow_card_reports, "cycle_time"), "std_dev_cycle_time": std_dev(workflow_card_reports, "cycle_time"), } return render(request, "boards/cards/workflow_card_report_list.html", replacements)
def view_week_summary(request, board_id, member_id="all", week_of_year=None): current_member = None if user_is_member(request.user): current_member = request.user.member board = get_user_board_or_404(request.user, board_id) replacements = {"board": board, "member": current_member} if request.method == "POST": form = WeekSummaryFilterForm(post_data=request.POST, board=board) if form.is_valid(): year = form.cleaned_data.get("year") week = form.cleaned_data.get("week") member_id = form.cleaned_data.get("member") week_of_year = "{0}W{1}".format(year, week) return HttpResponseRedirect(reverse("boards:view_week_summary", args=(board_id, member_id, week_of_year,))) year = None week = None if week_of_year is None: now = timezone.now() year = now.year week = int(get_iso_week_of_year(now)) week_of_year = "{0}W{1}".format(year, week) if week is None or year is None: matches = re.match(r"^(?P<year>\d{4})W(?P<week>\d{2})$", week_of_year) if matches: year = int(matches.group("year")) week = int(matches.group("week")) form = WeekSummaryFilterForm(initial={"year": year, "week": week, "member": member_id}, board=board) replacements["form"] = form replacements["week_of_year"] = week_of_year # Done cards that are of this member member_filter = {} if member_id != "all": member_filter = {"members": member_id} # Date limits of the selected week week_start_date = Week(year, week).monday() week_end_date = Week(year, week).friday() # Getting the cards that were completed in the selected week for the selected user completed_cards = board.cards.\ filter(list__type="done", movements__type="forward", movements__destination_list__type="done", movements__datetime__gte=week_start_date, movements__datetime__lte=week_end_date)\ .filter(**member_filter).\ order_by("last_activity_datetime") replacements["completed_cards"] = completed_cards # Time spent developing on this week if member_id == "all": spent_time = board.get_spent_time([week_start_date, week_end_date]) adjusted_spent_time = board.get_spent_time([week_start_date, week_end_date]) else: member = board.members.get(id=member_id) spent_time = board.get_spent_time([week_start_date, week_end_date], member) adjusted_spent_time = board.get_spent_time([week_start_date, week_end_date], member) replacements["selected_member"] = member replacements["spent_time"] = spent_time replacements["adjusted_spent_time"] = adjusted_spent_time replacements["week_start_date"] = week_start_date replacements["week_end_date"] = week_end_date return render(request, "boards/week_summary.html", replacements)
def view_gantt_chart(request, board_id): board = get_user_board_or_404(request.user, board_id) member = None visitor = None if user_is_member(request.user): member = request.user.member elif user_is_visitor(request.user, board): visitor = request.user board_cards = board.cards.filter( list__type__in=List.STARTED_CARD_LIST_TYPES) cards = [] for board_card in board_cards: # Task start start_date = board_card.start_datetime if start_date is None: start_date = board_card.creation_datetime # Task end if board_card.due_datetime is not None: end_date = board_card.due_datetime elif board_card.list.type == "done": end_date = board_card.end_datetime else: end_date = start_date + timedelta(days=1) # Color of task task_color = "blue" # Percentage of completion of the task if board_card.list.type == "development": completion_percentage = 0 elif board_card.list.type == "after_development_in_review": completion_percentage = 75 elif board_card.list.type == "after_development_waiting_release": completion_percentage = 85 else: completion_percentage = 100 # Parent Task blocking_cards = board_card.blocking_cards.all().order_by( "creation_datetime") parent_card = 0 if blocking_cards.exists(): parent_card = blocking_cards[0].id # Dependant tasks blocked_cards = board_card.blocked_cards.all() dependant_cards = "" if blocked_cards.exists(): for blocked_card in blocked_cards: dependant_cards += ",".format(blocked_card.id) dependant_cards = dependant_cards[:-1] members = board_card.members.all() for member in members: card = { "pID": board_card.id, "pName": "{0}".format(board_card.short_url, member.external_username), "pStart": start_date.strftime("%Y-%m-%d"), "pEnd": end_date.strftime("%Y-%m-%d"), "pClass": "gtask{0}".format(task_color), "pLink": reverse("boards:view_card", args=(board_id, board_card.id)), "pMile": 0, "pRes": member.external_username, "pComp": completion_percentage, "pGroup": 1 if blocked_cards.exists() else 0, "pParent": parent_card, "pOpen": 0, "pDepend": dependant_cards, "pCaption": board_card.name, "pNotes": "{0}\\\n{1}".format( board_card.name, board_card.description.replace("\n", "\\\n")) } cards.append(card) replacements = { "board": board, "cards": cards, "member": member, "visitor": visitor, } return render(request, "boards/gantt_chart.html", replacements)