Merge pull request #257 from bornhack/feature/team_refactor
Team site refactor
This commit is contained in:
commit
2ad0568f64
|
@ -62,7 +62,7 @@ a, a:active, a:focus {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav li a {
|
#top-navbar > .nav li a {
|
||||||
padding: 30px 7px;
|
padding: 30px 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ class Team(CampRelatedModel):
|
||||||
return '{} ({})'.format(self.name, self.camp)
|
return '{} ({})'.format(self.name, self.camp)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('teams:detail', kwargs={'camp_slug': self.camp.slug, 'team_slug': self.slug})
|
return reverse_lazy('teams:general', kwargs={'camp_slug': self.camp.slug, 'team_slug': self.slug})
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
# generate slug if needed
|
# generate slug if needed
|
||||||
|
@ -216,6 +216,7 @@ class Team(CampRelatedModel):
|
||||||
|
|
||||||
|
|
||||||
class TeamMember(CampRelatedModel):
|
class TeamMember(CampRelatedModel):
|
||||||
|
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
'auth.User',
|
'auth.User',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
|
|
|
@ -13,6 +13,6 @@ Fix IRC permissions for NickServ user {{ request.user.profile.nickserv_username
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<button class="btn btn-success" type="submit"><i class="fas fa-check"></i> Yes Please</button>
|
<button class="btn btn-success" type="submit"><i class="fas fa-check"></i> Yes Please</button>
|
||||||
<a href="{% url 'teams:detail' camp_slug=team.camp.slug team_slug=team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
<a href="{% url 'teams:general' camp_slug=team.camp.slug team_slug=team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ task.name }}
|
{{ task.name }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><h4>Task: {{ task.name }} ({% if not task.completed %}Not {% endif %}Completed)</h4></div>
|
<div class="panel-heading"><h4>Task: {{ task.name }} ({% if not task.completed %}Not {% endif %}Completed)</h4></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Create Task
|
||||||
for {{ team.name }} Team
|
for {{ team.name }} Team
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4>
|
<h4>
|
||||||
|
@ -30,7 +30,7 @@ for {{ team.name }} Team
|
||||||
<button type="submit" class="btn btn-primary">{% if form.instance.id %}Save{% else %}Create{% endif %}</button>
|
<button type="submit" class="btn btn-primary">{% if form.instance.id %}Save{% else %}Create{% endif %}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer"><i>This task belongs to the <a href="{% url 'teams:detail' team_slug=team.slug camp_slug=team.camp.slug %}">{{ team.name }} Team</a></i></div>
|
<div class="panel-footer"><i>This task belongs to the <a href="{% url 'teams:general' team_slug=team.slug camp_slug=team.camp.slug %}">{{ team.name }} Team</a></i></div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
77
src/teams/templates/team_base.html
Normal file
77
src/teams/templates/team_base.html
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load commonmark %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load teams_tags %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Team: {{ team.name }} | {{ block.super }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>{{ team.name }} Team</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2">
|
||||||
|
<ul class="nav nav-pills nav-stacked">
|
||||||
|
<li {% if view.active_menu == "general" %}class="active"{% endif %}>
|
||||||
|
<a href="{% url "teams:general" camp_slug=team.camp.slug team_slug=team.slug %}">
|
||||||
|
General
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li {% if view.active_menu == "members" %}class="active"{% endif %}>
|
||||||
|
<a href="{% url "teams:members" camp_slug=team.camp.slug team_slug=team.slug %}">
|
||||||
|
Members
|
||||||
|
{% if request.user in team.responsible_members.all and team.unapproved_members %}
|
||||||
|
<span class="label label-danger">Pending</span>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li {% if view.active_menu == "tasks" %}class="active"{% endif %}>
|
||||||
|
<a href="{% url "teams:tasks" camp_slug=team.camp.slug team_slug=team.slug %}">
|
||||||
|
Tasks
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% if request.user in team.responsible_members.all %}
|
||||||
|
<li {% if view.active_menu == "info_categories" %}class="active"{% endif %}>
|
||||||
|
<a href="{% url "teams:info_categories" camp_slug=team.camp.slug team_slug=team.slug %}">
|
||||||
|
Info categories
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
|
||||||
|
{% if request.user in team.members.all %}
|
||||||
|
<p>Your membership status: <b>{% membershipstatus user team %}</b></p>
|
||||||
|
|
||||||
|
{% if request.user in team.responsible_members.all %}
|
||||||
|
<a href="{% url 'teams:manage' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-cog"></i> Manage Team</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{% if team.needs_members %}
|
||||||
|
<b>This team is looking for members!</b> <a href="{% url 'teams:join' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-xs btn-success"><i class="fas fa-plus"></i> Join Team</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-10">
|
||||||
|
|
||||||
|
{% block team_content %}{% endblock %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,155 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
{% load commonmark %}
|
|
||||||
{% load bootstrap3 %}
|
|
||||||
{% load teams_tags %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Team: {{ team.name }} | {{ block.super }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>{{ team.name }} Team Details</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h4>Description</h4>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{{ team.description|untrustedcommonmark }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Team communications #}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h4>Communication Channels</h4>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{{ team.camp.title }} teams primarily use mailing lists and IRC to communicate. The <b>{{ team.name }} team</b> can be contacted in the following ways:</p>
|
|
||||||
|
|
||||||
<h5>Mailing List</h5>
|
|
||||||
{% if team.mailing_list and request.user in team.approved_members.all %}
|
|
||||||
<p>The {{ team.name }} Team mailinglist is <b>{{ team.mailing_list }}</b>{% if team.mailing_list_archive_public %}, and the archives are publicly available{% endif %}. You should sign up for the list if you haven't already.</p>
|
|
||||||
{% elif team.mailing_list and team.mailinglist_nonmember_posts %}
|
|
||||||
<p>The {{ team.name }} Team mailinglist is <b>{{ team.mailing_list }}</b>{% if team.mailing_list_archive_public %}, and the archives are publicly available{% endif %}. You do not need to be a member of the list to post to it.</p>
|
|
||||||
{% else %}
|
|
||||||
<p>The {{ team.name }} Team does not have a public mailing list, but it can be contacted through our main email <a href="mailto:info@bornhack.dk">info@bornhack.dk</a>.
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h5>IRC Channel</h5>
|
|
||||||
{% if team.public_irc_channel_name %}
|
|
||||||
<p>The {{ team.name }} Team public IRC channel is <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ team.public_irc_channel_name }}">{{ team.public_irc_channel_name }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.
|
|
||||||
{% else %}
|
|
||||||
<p>The {{ team.name }} Team does not have a public IRC channel, but it can be reached through our main IRC channel <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ IRCBOT_PUBLIC_CHANNEL }}">{{ IRCBOT_PUBLIC_CHANNEL }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if request.user in team.approved_members.all and team.private_irc_channel_name %}
|
|
||||||
<p>The {{ team.name }} Team private IRC channel is <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ team.private_irc_channel_name }}">{{ team.private_irc_channel_name }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include 'includes/team_tasks.html' %}
|
|
||||||
|
|
||||||
{# Team members #}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h4>Members</h4>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>The following <b>{{ team.approved_members.count }}</b> people {% if team.unapproved_members.count %}(and {{ team.unapproved_members.count }} pending){% endif %} are members of the <b>{{ team.name }} Team</b>:</p>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Name
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Status
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for teammember in team.memberships.all %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{{ teammember.user.profile.get_public_credit_name }} {% if teammember.user == request.user %}(this is you!){% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
Team {% if teammember.responsible %}Responsible{% else %}Member{% endif %}
|
|
||||||
{% if not teammember.approved %}(pending approval){% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Your membership status: <b>{% membershipstatus user team %}</b></p>
|
|
||||||
|
|
||||||
{% if request.user in team.members.all %}
|
|
||||||
{% if team.irc_channel and team.irc_channel_managed and request.user.profile.nickserv_username %}
|
|
||||||
<a href="{% url 'teams:fix_irc_acl' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-wrench"></i> Fix IRC ACL</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'teams:leave' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-danger"><i class="fas fa-times"></i> Leave Team</a>
|
|
||||||
{% else %}
|
|
||||||
{% if team.needs_members %}
|
|
||||||
<b>This team is looking for members!</b> <a href="{% url 'teams:join' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-xs btn-success"><i class="fas fa-plus"></i> Join Team</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if request.user in team.responsible_members.all %}
|
|
||||||
<a href="{% url 'teams:manage' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-cog"></i> Manage Team</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Team info categories section - only visible for team responsible #}
|
|
||||||
{% if request.user in team.responsible_members.all and team.info_categories.exists %}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h4>Info Categories</h4>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
|
|
||||||
{% for info_category in team.info_categories.all %}
|
|
||||||
|
|
||||||
<h4>{{ info_category.headline }}</h4>
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Item name</th>
|
|
||||||
<th>Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in info_category.infoitems.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ item.headline }}</td>
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'teams:info_item_update' camp_slug=camp.slug team_slug=team.slug category_anchor=info_category.anchor item_anchor=item.anchor %}"
|
|
||||||
class="btn btn-primary btn-sm">
|
|
||||||
<i class="fas fa-edit"></i> Edit
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<a href="{% url 'teams:info_item_create' camp_slug=camp.slug team_slug=team.slug category_anchor=info_category.anchor %}" class="btn btn-primary"><i class="fas fa-plus"></i> Create Info Item</a>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
48
src/teams/templates/team_general.html
Normal file
48
src/teams/templates/team_general.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends 'team_base.html' %}
|
||||||
|
{% load commonmark %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load teams_tags %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block team_content %}
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>Description</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ team.description|untrustedcommonmark }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Team communications #}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>Communication Channels</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ team.camp.title }} teams primarily use mailing lists and IRC to communicate. The <b>{{ team.name }} team</b> can be contacted in the following ways:</p>
|
||||||
|
|
||||||
|
<h5>Mailing List</h5>
|
||||||
|
{% if team.mailing_list and request.user in team.approved_members.all %}
|
||||||
|
<p>The {{ team.name }} Team mailinglist is <b>{{ team.mailing_list }}</b>{% if team.mailing_list_archive_public %}, and the archives are publicly available{% endif %}. You should sign up for the list if you haven't already.</p>
|
||||||
|
{% elif team.mailing_list and team.mailinglist_nonmember_posts %}
|
||||||
|
<p>The {{ team.name }} Team mailinglist is <b>{{ team.mailing_list }}</b>{% if team.mailing_list_archive_public %}, and the archives are publicly available{% endif %}. You do not need to be a member of the list to post to it.</p>
|
||||||
|
{% else %}
|
||||||
|
<p>The {{ team.name }} Team does not have a public mailing list, but it can be contacted through our main email <a href="mailto:info@bornhack.dk">info@bornhack.dk</a>.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h5>IRC Channel</h5>
|
||||||
|
{% if team.public_irc_channel_name %}
|
||||||
|
<p>The {{ team.name }} Team public IRC channel is <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ team.public_irc_channel_name }}">{{ team.public_irc_channel_name }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.
|
||||||
|
{% else %}
|
||||||
|
<p>The {{ team.name }} Team does not have a public IRC channel, but it can be reached through our main IRC channel <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ IRCBOT_PUBLIC_CHANNEL }}">{{ IRCBOT_PUBLIC_CHANNEL }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user in team.approved_members.all and team.private_irc_channel_name %}
|
||||||
|
<p>The {{ team.name }} Team private IRC channel is <a href="irc://{{ IRCBOT_SERVER_HOSTNAME }}/{{ team.private_irc_channel_name }}">{{ team.private_irc_channel_name }} on {{ IRCBOT_SERVER_HOSTNAME }}</a>.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
48
src/teams/templates/team_info_categories.html
Normal file
48
src/teams/templates/team_info_categories.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends 'team_base.html' %}
|
||||||
|
{% load commonmark %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load teams_tags %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block team_content %}
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>Info Categories</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
{% for info_category in team.info_categories.all %}
|
||||||
|
|
||||||
|
<h4>{{ info_category.headline }}</h4>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Item name</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in info_category.infoitems.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.headline }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'teams:info_item_update' camp_slug=camp.slug team_slug=team.slug category_anchor=info_category.anchor item_anchor=item.anchor %}"
|
||||||
|
class="btn btn-primary btn-sm">
|
||||||
|
<i class="fas fa-edit"></i> Edit
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<a href="{% url 'teams:info_item_create' camp_slug=camp.slug team_slug=team.slug category_anchor=info_category.anchor %}" class="btn btn-primary"><i class="fas fa-plus"></i> Create Info Item</a>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ Create Info item
|
||||||
in {{ form.instance.category.headline }}
|
in {{ form.instance.category.headline }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4>
|
<h4>
|
|
@ -1,26 +1,28 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% if object %}
|
{% if object %}
|
||||||
Editing "{{ object.headline }}"
|
Editing "{{ object.headline }}"
|
||||||
|
in "{{ form.instance.category.headline }}"
|
||||||
{% else %}
|
{% else %}
|
||||||
Create Info item
|
Create Info item
|
||||||
|
in "{{ category.headline }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
in "{{ form.instance.category.headline }}"
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4>
|
<h4>
|
||||||
{% if object %}
|
{% if object %}
|
||||||
Editing "{{ object.headline }}"
|
Editing "{{ object.headline }}"
|
||||||
|
in "{{ object.category.headline }}"
|
||||||
{% else %}
|
{% else %}
|
||||||
Create Info Item
|
Create Info Item
|
||||||
|
in "{{ category.headline }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
in "{{ object.category.headline }}"
|
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
@ -36,6 +38,6 @@ in "{{ form.instance.category.headline }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer"><i>This info item belongs to the <a href="{% url 'teams:detail' team_slug=team.slug camp_slug=team.camp.slug %}">{{ team.name }} Team</a></i></div>
|
<div class="panel-footer"><i>This info item belongs to the <a href="{% url 'teams:general' team_slug=team.slug camp_slug=team.camp.slug %}">{{ team.name }} Team</a></i></div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,11 +1,11 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
Join Team: {{ team.name }} | {{ block.super }}
|
Join Team: {{ team.name }} | {{ block.super }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
|
|
||||||
<p class="lead">Really join the <b>{{ team.name }}</b> Team for <b>{{ team.camp.title }}</b>?</p>
|
<p class="lead">Really join the <b>{{ team.name }}</b> Team for <b>{{ team.camp.title }}</b>?</p>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
Leave Team: {{ team.name }} | {{ block.super }}
|
Leave Team: {{ team.name }} | {{ block.super }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
|
|
||||||
<h3>Leave {{ team.name }} Team</h3>
|
<h3>Leave {{ team.name }} Team</h3>
|
||||||
<p class="lead">Really leave the <b>{{ team.name }}</b> team?<p>
|
<p class="lead">Really leave the <b>{{ team.name }}</b> team?<p>
|
||||||
|
|
|
@ -33,7 +33,7 @@ Teams | {{ block.super }}
|
||||||
{% for team in teams %}
|
{% for team in teams %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'teams:detail' camp_slug=camp.slug team_slug=team.slug %}">
|
<a href="{% url 'teams:general' camp_slug=camp.slug team_slug=team.slug %}">
|
||||||
{{ team.name }} Team
|
{{ team.name }} Team
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -63,7 +63,7 @@ Teams | {{ block.super }}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group-vertical">
|
<div class="btn-group-vertical">
|
||||||
<a class="btn btn-primary" href="{% url 'teams:detail' camp_slug=camp.slug team_slug=team.slug %}"><i class="fas fa-search"></i> Details</a>
|
<a class="btn btn-primary" href="{% url 'teams:general' camp_slug=camp.slug team_slug=team.slug %}"><i class="fas fa-search"></i> Details</a>
|
||||||
{% if request.user in team.responsible_members.all %}
|
{% if request.user in team.responsible_members.all %}
|
||||||
<a href="{% url 'teams:manage' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-cog"></i> Manage</a>
|
<a href="{% url 'teams:manage' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-cog"></i> Manage</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
Manage Team: {{ team.name }} | {{ block.super }}
|
Manage Team: {{ team.name }} | {{ block.super }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><h4>Manage {{ team.name }} Team</h4></div>
|
<div class="panel-heading"><h4>Manage {{ team.name }} Team</h4></div>
|
||||||
<div class="panel-body" style="margin-left: 1em; margin-right: 1em;">
|
<div class="panel-body" style="margin-left: 1em; margin-right: 1em;">
|
||||||
|
@ -18,85 +18,11 @@ Manage Team: {{ team.name }} | {{ block.super }}
|
||||||
|
|
||||||
{% buttons %}
|
{% buttons %}
|
||||||
<button class="btn btn-success pull-right" type="submit"><i class="fas fa-check"></i> Save Team</button>
|
<button class="btn btn-success pull-right" type="submit"><i class="fas fa-check"></i> Save Team</button>
|
||||||
<a class="btn btn-primary pull-right" href="{% url 'teams:detail' team_slug=team.slug camp_slug=camp.slug %}"><i class="fas fa-times"></i> Cancel</a>
|
<a class="btn btn-primary pull-right" href="{% url 'teams:general' team_slug=team.slug camp_slug=camp.slug %}"><i class="fas fa-times"></i> Cancel</a>
|
||||||
{% endbuttons %}
|
{% endbuttons %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading"><h4>Manage {{ team.name }} Team Members</h4></div>
|
|
||||||
<div class="panel-body" style="margin-left: 1em; margin-right: 1em;">
|
|
||||||
{% if team.teammember_set.exists %}
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Username
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Name
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Email
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Description
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Public Credit Name
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Membership
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Action
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for membership in team.teammember_set.all %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{{ membership.user }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ membership.user.profile.name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ membership.user.profile.email }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ membership.user.profile.description }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ membership.user.profile.public_credit_name|default:"N/A" }}
|
|
||||||
{% if membership.user.profile.public_credit_name and not membership.user.profile.public_credit_name_approved %}<span class="text-warning">(name not approved)</span>{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if membership.approved %}member{% else %}pending{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group-vertical">
|
|
||||||
<a class="btn btn-danger" href="{% url 'teams:teammember_remove' camp_slug=camp.slug pk=membership.id %}"><i class="fas fa-trash-o"></i> Remove Member</a>
|
|
||||||
{% if not membership.approved %}
|
|
||||||
<a class="btn btn-success" href="{% url 'teams:teammember_approve' camp_slug=camp.slug pk=membership.id %}"><i class="fas fa-check"></i> Approve Member</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p>No members found!</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% include 'includes/team_tasks.html' %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
86
src/teams/templates/team_members.html
Normal file
86
src/teams/templates/team_members.html
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
{% extends 'team_base.html' %}
|
||||||
|
{% load commonmark %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load teams_tags %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block team_content %}
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>Members</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>The following <b>{{ team.approved_members.count }}</b> people {% if team.unapproved_members.count %}(and {{ team.unapproved_members.count }} pending){% endif %} are members of the <b>{{ team.name }} Team</b>:</p>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Name
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Status
|
||||||
|
</th>
|
||||||
|
{% if request.user in team.responsible_members.all %}
|
||||||
|
<th>
|
||||||
|
Action
|
||||||
|
</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for member in team.memberships.all %}
|
||||||
|
{% if member.approved or not member.approved and request.user in team.responsible_members.all %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ member.user.profile.get_public_credit_name }} {% if member.user == request.user %}(this is you!){% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Team {% if member.responsible %}Responsible{% else %}Member{% endif %}
|
||||||
|
{% if not member.approved %}(pending approval){% endif %}
|
||||||
|
</td>
|
||||||
|
{% if request.user in team.responsible_members.all %}
|
||||||
|
<td>
|
||||||
|
<div class="btn-group-vertical">
|
||||||
|
<a class="btn btn-danger"
|
||||||
|
href="{% url 'teams:member_remove' camp_slug=camp.slug team_slug=team.slug pk=member.id %}">
|
||||||
|
<i class="fas fa-trash"></i> Remove
|
||||||
|
</a>
|
||||||
|
{% if not member.approved %}
|
||||||
|
<a class="btn btn-success"
|
||||||
|
href="{% url 'teams:member_approve' camp_slug=camp.slug team_slug=team.slug pk=member.id %}">
|
||||||
|
<i class="fas fa-check"></i> Approve
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% empty %}
|
||||||
|
<p>No members found!</p>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if request.user.authorized %}
|
||||||
|
|
||||||
|
<p>Your membership status: <b>{% membershipstatus user team %}</b></p>
|
||||||
|
|
||||||
|
{% if request.user in team.members.all %}
|
||||||
|
{% if team.irc_channel and team.irc_channel_managed and request.user.profile.nickserv_username %}
|
||||||
|
<a href="{% url 'teams:fix_irc_acl' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fas fa-wrench"></i> Fix IRC ACL</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{% url 'teams:leave' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-danger"><i class="fas fa-times"></i> Leave Team</a>
|
||||||
|
{% else %}
|
||||||
|
{% if team.needs_members %}
|
||||||
|
<b>This team is looking for members!</b> <a href="{% url 'teams:join' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-xs btn-success"><i class="fas fa-plus"></i> Join Team</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -1,3 +1,10 @@
|
||||||
|
{% extends 'team_base.html' %}
|
||||||
|
{% load commonmark %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load teams_tags %}
|
||||||
|
|
||||||
|
{% block team_content %}
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4>Tasks</h4>
|
<h4>Tasks</h4>
|
||||||
|
@ -10,7 +17,7 @@
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>When</th>
|
<th>When</th>
|
||||||
<th>Completed</th>
|
<th>Completed?</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -41,4 +48,4 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,11 +1,11 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
Approve team member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team
|
Approve team member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
|
|
||||||
<h3>Approve member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team</h3>
|
<h3>Approve member {{ teammember.user.profile.name }} for the {{ teammember.team.name }} team</h3>
|
||||||
<p class="lead">Really approve the user <b>{{ teammember.user.profile.name }}</b> for the {{ teammember.team.name }} team? The user will receive an email with a message.<p>
|
<p class="lead">Really approve the user <b>{{ teammember.user.profile.name }}</b> for the {{ teammember.team.name }} team? The user will receive an email with a message.<p>
|
||||||
|
@ -13,6 +13,7 @@ Approve team member {{ teammember.user.profile.name }} for the {{ teammember.tea
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<button class="btn btn-success" type="submit"><i class="fas fa-check"></i> Add teammember</button>
|
<button class="btn btn-success" type="submit"><i class="fas fa-check"></i> Add teammember</button>
|
||||||
<a href="{% url 'teams:detail' camp_slug=teammember.team.camp.slug team_slug=teammember.team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
<a href="{% url 'teams:general' camp_slug=teammember.team.camp.slug team_slug=teammember.team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'team_base.html' %}
|
||||||
{% load commonmark %}
|
{% load commonmark %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team
|
Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block team_content %}
|
||||||
|
|
||||||
<h3>Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team</h3>
|
<h3>Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.name }} team</h3>
|
||||||
<p class="lead">Really remove the user <b>{{ teammember.user.profile.name }}</b> from the {{ teammember.team.name }} team? The user will receive an email with a message.<p>
|
<p class="lead">Really remove the user <b>{{ teammember.user.profile.name }}</b> from the {{ teammember.team.name }} team? The user will receive an email with a message.<p>
|
||||||
|
@ -13,6 +13,6 @@ Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.nam
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<button class="btn btn-danger" type="submit"><i class="fas fa-trash-o"></i> Remove teammember</button>
|
<button class="btn btn-danger" type="submit"><i class="fas fa-trash-o"></i> Remove teammember</button>
|
||||||
<a href="{% url 'teams:detail' camp_slug=teammember.team.camp.slug team_slug=teammember.team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
<a href="{% url 'teams:general' camp_slug=teammember.team.camp.slug team_slug=teammember.team.slug %}" class="btn btn-default" type="submit"><i class="fas fa-times"></i> Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -2,17 +2,28 @@ from django.urls import path, include
|
||||||
|
|
||||||
from teams.views.base import (
|
from teams.views.base import (
|
||||||
TeamListView,
|
TeamListView,
|
||||||
TeamMemberRemoveView,
|
TeamGeneralView,
|
||||||
TeamMemberApproveView,
|
|
||||||
TeamDetailView,
|
|
||||||
TeamJoinView,
|
|
||||||
TeamLeaveView,
|
|
||||||
TeamManageView,
|
TeamManageView,
|
||||||
FixIrcAclView,
|
FixIrcAclView,
|
||||||
)
|
)
|
||||||
from teams.views.info import InfoItemUpdateView, InfoItemCreateView, InfoItemDeleteView
|
|
||||||
|
from teams.views.members import (
|
||||||
|
TeamMembersView,
|
||||||
|
TeamMemberRemoveView,
|
||||||
|
TeamMemberApproveView,
|
||||||
|
TeamJoinView,
|
||||||
|
TeamLeaveView,
|
||||||
|
)
|
||||||
|
|
||||||
|
from teams.views.info import (
|
||||||
|
InfoCategoriesListView,
|
||||||
|
InfoItemUpdateView,
|
||||||
|
InfoItemCreateView,
|
||||||
|
InfoItemDeleteView,
|
||||||
|
)
|
||||||
|
|
||||||
from teams.views.tasks import (
|
from teams.views.tasks import (
|
||||||
|
TeamTasksView,
|
||||||
TaskCreateView,
|
TaskCreateView,
|
||||||
TaskDetailView,
|
TaskDetailView,
|
||||||
TaskUpdateView,
|
TaskUpdateView,
|
||||||
|
@ -26,26 +37,12 @@ urlpatterns = [
|
||||||
TeamListView.as_view(),
|
TeamListView.as_view(),
|
||||||
name='list'
|
name='list'
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
'members/', include([
|
|
||||||
path(
|
|
||||||
'<int:pk>/remove/',
|
|
||||||
TeamMemberRemoveView.as_view(),
|
|
||||||
name='teammember_remove',
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'<int:pk>/approve/',
|
|
||||||
TeamMemberApproveView.as_view(),
|
|
||||||
name='teammember_approve',
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
'<slug:team_slug>/', include([
|
'<slug:team_slug>/', include([
|
||||||
path(
|
path(
|
||||||
'',
|
'',
|
||||||
TeamDetailView.as_view(),
|
TeamGeneralView.as_view(),
|
||||||
name='detail'
|
name='general'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'join/',
|
'join/',
|
||||||
|
@ -67,8 +64,32 @@ urlpatterns = [
|
||||||
FixIrcAclView.as_view(),
|
FixIrcAclView.as_view(),
|
||||||
name='fix_irc_acl',
|
name='fix_irc_acl',
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
'members/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
TeamMembersView.as_view(),
|
||||||
|
name='members'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'<int:pk>/remove/',
|
||||||
|
TeamMemberRemoveView.as_view(),
|
||||||
|
name='member_remove',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'<int:pk>/approve/',
|
||||||
|
TeamMemberApproveView.as_view(),
|
||||||
|
name='member_approve',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
'tasks/', include([
|
'tasks/', include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
TeamTasksView.as_view(),
|
||||||
|
name='tasks',
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
'create/',
|
'create/',
|
||||||
TaskCreateView.as_view(),
|
TaskCreateView.as_view(),
|
||||||
|
@ -92,7 +113,15 @@ urlpatterns = [
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'info/<slug:category_anchor>/', include([
|
'info/',
|
||||||
|
include([
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
InfoCategoriesListView.as_view(),
|
||||||
|
name='info_categories'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'<slug:category_anchor>/', include([
|
||||||
path(
|
path(
|
||||||
'create/',
|
'create/',
|
||||||
InfoItemCreateView.as_view(),
|
InfoItemCreateView.as_view(),
|
||||||
|
@ -114,6 +143,8 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
])
|
||||||
|
)
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,11 +7,8 @@ from django.contrib import messages
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from profiles.models import Profile
|
from .mixins import EnsureTeamResponsibleMixin
|
||||||
|
|
||||||
from .mixins import EnsureTeamResponsibleMixin, EnsureTeamMemberResponsibleMixin
|
|
||||||
from ..models import Team, TeamMember
|
from ..models import Team, TeamMember
|
||||||
from ..email import add_added_membership_email, add_removed_membership_email
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||||
|
@ -23,14 +20,15 @@ class TeamListView(CampViewMixin, ListView):
|
||||||
context_object_name = 'teams'
|
context_object_name = 'teams'
|
||||||
|
|
||||||
|
|
||||||
class TeamDetailView(CampViewMixin, DetailView):
|
class TeamGeneralView(CampViewMixin, DetailView):
|
||||||
template_name = "team_detail.html"
|
template_name = "team_general.html"
|
||||||
context_object_name = 'team'
|
context_object_name = 'team'
|
||||||
model = Team
|
model = Team
|
||||||
slug_url_kwarg = 'team_slug'
|
slug_url_kwarg = 'team_slug'
|
||||||
|
active_menu = 'general'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(TeamDetailView, self).get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['IRCBOT_SERVER_HOSTNAME'] = settings.IRCBOT_SERVER_HOSTNAME
|
context['IRCBOT_SERVER_HOSTNAME'] = settings.IRCBOT_SERVER_HOSTNAME
|
||||||
context['IRCBOT_PUBLIC_CHANNEL'] = settings.IRCBOT_PUBLIC_CHANNEL
|
context['IRCBOT_PUBLIC_CHANNEL'] = settings.IRCBOT_PUBLIC_CHANNEL
|
||||||
return context
|
return context
|
||||||
|
@ -39,102 +37,20 @@ class TeamDetailView(CampViewMixin, DetailView):
|
||||||
class TeamManageView(CampViewMixin, EnsureTeamResponsibleMixin, UpdateView):
|
class TeamManageView(CampViewMixin, EnsureTeamResponsibleMixin, UpdateView):
|
||||||
model = Team
|
model = Team
|
||||||
template_name = "team_manage.html"
|
template_name = "team_manage.html"
|
||||||
fields = ['description', 'needs_members', 'public_irc_channel_name', 'public_irc_channel_bot', 'public_irc_channel_managed', 'private_irc_channel_name', 'private_irc_channel_bot', 'private_irc_channel_managed']
|
fields = ['description', 'needs_members', 'public_irc_channel_name',
|
||||||
|
'public_irc_channel_bot', 'public_irc_channel_managed',
|
||||||
|
'private_irc_channel_name', 'private_irc_channel_bot',
|
||||||
|
'private_irc_channel_managed']
|
||||||
slug_url_kwarg = 'team_slug'
|
slug_url_kwarg = 'team_slug'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('teams:detail', kwargs={'camp_slug': self.camp.slug, 'team_slug': self.get_object().slug})
|
return reverse_lazy('teams:general', kwargs={'camp_slug': self.camp.slug, 'team_slug': self.get_object().slug})
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
messages.success(self.request, "Team has been saved")
|
messages.success(self.request, "Team has been saved")
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class TeamJoinView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
|
||||||
template_name = "team_join.html"
|
|
||||||
model = Team
|
|
||||||
fields = []
|
|
||||||
slug_url_kwarg = 'team_slug'
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
if not Profile.objects.get(user=request.user).description:
|
|
||||||
messages.warning(
|
|
||||||
request,
|
|
||||||
"Please fill the description in your profile before joining a team"
|
|
||||||
)
|
|
||||||
return redirect('teams:list', camp_slug=self.camp.slug)
|
|
||||||
|
|
||||||
if request.user in self.get_object().members.all():
|
|
||||||
messages.warning(request, "You are already a member of this team")
|
|
||||||
return redirect('teams:list', camp_slug=self.camp.slug)
|
|
||||||
|
|
||||||
if not self.get_object().needs_members:
|
|
||||||
messages.warning(request, "This team does not need members right now")
|
|
||||||
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
|
||||||
|
|
||||||
return super().get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
TeamMember.objects.create(team=self.get_object(), user=self.request.user)
|
|
||||||
messages.success(self.request, "You request to join the team %s has been registered, thank you." % self.get_object().name)
|
|
||||||
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
|
||||||
|
|
||||||
|
|
||||||
class TeamLeaveView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
|
||||||
template_name = "team_leave.html"
|
|
||||||
model = Team
|
|
||||||
fields = []
|
|
||||||
slug_url_kwarg = 'team_slug'
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
if request.user not in self.get_object().members.all():
|
|
||||||
messages.warning(request, "You are not a member of this team")
|
|
||||||
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
|
||||||
|
|
||||||
return super().get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
TeamMember.objects.filter(team=self.get_object(), user=self.request.user).delete()
|
|
||||||
messages.success(self.request, "You are no longer a member of the team %s" % self.get_object().name)
|
|
||||||
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TeamMemberRemoveView(LoginRequiredMixin, CampViewMixin, EnsureTeamMemberResponsibleMixin, UpdateView):
|
|
||||||
template_name = "teammember_remove.html"
|
|
||||||
model = TeamMember
|
|
||||||
fields = []
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
form.instance.delete()
|
|
||||||
if add_removed_membership_email(form.instance):
|
|
||||||
messages.success(self.request, "Team member removed")
|
|
||||||
else:
|
|
||||||
messages.success(self.request, "Team member removed (unable to add email to outgoing queue).")
|
|
||||||
logger.error(
|
|
||||||
'Unable to add removed email to outgoing queue for teammember: {}'.format(form.instance)
|
|
||||||
)
|
|
||||||
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=form.instance.team.slug)
|
|
||||||
|
|
||||||
|
|
||||||
class TeamMemberApproveView(LoginRequiredMixin, CampViewMixin, EnsureTeamMemberResponsibleMixin, UpdateView):
|
|
||||||
template_name = "teammember_approve.html"
|
|
||||||
model = TeamMember
|
|
||||||
fields = []
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
form.instance.approved = True
|
|
||||||
form.instance.save()
|
|
||||||
if add_added_membership_email(form.instance):
|
|
||||||
messages.success(self.request, "Team member approved")
|
|
||||||
else:
|
|
||||||
messages.success(self.request, "Team member removed (unable to add email to outgoing queue).")
|
|
||||||
logger.error(
|
|
||||||
'Unable to add approved email to outgoing queue for teammember: {}'.format(form.instance)
|
|
||||||
)
|
|
||||||
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=form.instance.team.slug)
|
|
||||||
|
|
||||||
|
|
||||||
class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
template_name = "fix_irc_acl.html"
|
template_name = "fix_irc_acl.html"
|
||||||
model = Team
|
model = Team
|
||||||
|
@ -151,17 +67,17 @@ class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
# check if the logged in user has an approved membership of this team
|
# check if the logged in user has an approved membership of this team
|
||||||
if request.user not in self.get_object().approved_members.all():
|
if request.user not in self.get_object().approved_members.all():
|
||||||
messages.error(request, 'No thanks')
|
messages.error(request, 'No thanks')
|
||||||
return redirect('teams:detail', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
return redirect('teams:general', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
||||||
|
|
||||||
# check if we manage the channel for this team
|
# check if we manage the channel for this team
|
||||||
if not self.get_object().irc_channel or not self.get_object().irc_channel_managed:
|
if not self.get_object().irc_channel or not self.get_object().irc_channel_managed:
|
||||||
messages.error(request, 'IRC functionality is disabled for this team, or the team channel is not managed by the bot')
|
messages.error(request, 'IRC functionality is disabled for this team, or the team channel is not managed by the bot')
|
||||||
return redirect('teams:detail', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
return redirect('teams:general', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
||||||
|
|
||||||
# check if user has a nickserv username
|
# check if user has a nickserv username
|
||||||
if not request.user.profile.nickserv_username:
|
if not request.user.profile.nickserv_username:
|
||||||
messages.error(request, 'Please go to your profile and set your NickServ username first. Make sure the account is registered with NickServ first!')
|
messages.error(request, 'Please go to your profile and set your NickServ username first. Make sure the account is registered with NickServ first!')
|
||||||
return redirect('teams:detail', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
return redirect('teams:general', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -177,7 +93,7 @@ class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
except TeamMember.DoesNotExist:
|
except TeamMember.DoesNotExist:
|
||||||
# this membership is already marked as membership.irc_channel_acl_ok=False, no need to do anything
|
# this membership is already marked as membership.irc_channel_acl_ok=False, no need to do anything
|
||||||
messages.error(request, 'No need, this membership is already marked as irc_channel_acl_ok=False, so the bot will fix the ACL soon')
|
messages.error(request, 'No need, this membership is already marked as irc_channel_acl_ok=False, so the bot will fix the ACL soon')
|
||||||
return redirect('teams:detail', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
return redirect('teams:general', camp_slug=self.get_object().camp.slug, team_slug=self.get_object().slug)
|
||||||
|
|
||||||
return super().get(
|
return super().get(
|
||||||
request, *args, **kwargs
|
request, *args, **kwargs
|
||||||
|
@ -195,5 +111,5 @@ class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
membership.irc_channel_acl_ok = False
|
membership.irc_channel_acl_ok = False
|
||||||
membership.save()
|
membership.save()
|
||||||
messages.success(self.request, "OK, hang on while we fix the permissions for your NickServ user '%s' for IRC channel '%s'" % (self.request.user.profile.nickserv_username, form.instance.irc_channel_name))
|
messages.success(self.request, "OK, hang on while we fix the permissions for your NickServ user '%s' for IRC channel '%s'" % (self.request.user.profile.nickserv_username, form.instance.irc_channel_name))
|
||||||
return redirect('teams:detail', camp_slug=form.instance.camp.slug, team_slug=form.instance.slug)
|
return redirect('teams:general', camp_slug=form.instance.camp.slug, team_slug=form.instance.slug)
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,39 @@
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.views.generic import CreateView, UpdateView, DeleteView
|
from django.views.generic import CreateView, UpdateView, DeleteView, ListView
|
||||||
from reversion.views import RevisionMixin
|
from reversion.views import RevisionMixin
|
||||||
|
|
||||||
from camps.mixins import CampViewMixin
|
from camps.mixins import CampViewMixin
|
||||||
from info.models import InfoItem, InfoCategory
|
from info.models import InfoItem, InfoCategory
|
||||||
from teams.views.mixins import EnsureTeamResponsibleMixin
|
from ..models import Team
|
||||||
|
from .mixins import EnsureTeamResponsibleMixin, TeamViewMixin
|
||||||
|
|
||||||
|
|
||||||
class InfoItemCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, CreateView):
|
class InfoCategoriesListView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, ListView):
|
||||||
|
model = InfoCategory
|
||||||
|
template_name = "team_info_categories.html"
|
||||||
|
slug_field = 'anchor'
|
||||||
|
active_menu = 'info_categories'
|
||||||
|
|
||||||
|
def get_team(self):
|
||||||
|
return Team.objects.get(
|
||||||
|
camp__slug=self.kwargs['camp_slug'],
|
||||||
|
slug=self.kwargs['team_slug']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InfoItemCreateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, CreateView):
|
||||||
model = InfoItem
|
model = InfoItem
|
||||||
template_name = "info_item_form.html"
|
template_name = "team_info_item_form.html"
|
||||||
fields = ['headline', 'body', 'anchor', 'weight']
|
fields = ['headline', 'body', 'anchor', 'weight']
|
||||||
slug_field = 'anchor'
|
slug_field = 'anchor'
|
||||||
|
active_menu = 'info_categories'
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_team(self):
|
||||||
context = super().get_context_data(**kwargs)
|
return Team.objects.get(
|
||||||
context['team'] = self.team
|
camp__slug=self.kwargs['camp_slug'],
|
||||||
return context
|
slug=self.kwargs['team_slug']
|
||||||
|
)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
info_item = form.save(commit=False)
|
info_item = form.save(commit=False)
|
||||||
|
@ -29,18 +45,28 @@ class InfoItemCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibl
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return self.team.get_absolute_url()
|
return self.team.get_absolute_url()
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['category'] = InfoCategory.objects.get(
|
||||||
|
team__camp__slug=self.kwargs['camp_slug'],
|
||||||
|
anchor=self.kwargs['category_anchor']
|
||||||
|
)
|
||||||
|
return context
|
||||||
|
|
||||||
class InfoItemUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, RevisionMixin, UpdateView):
|
|
||||||
|
class InfoItemUpdateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, RevisionMixin, UpdateView):
|
||||||
model = InfoItem
|
model = InfoItem
|
||||||
template_name = "info_item_form.html"
|
template_name = "team_info_item_form.html"
|
||||||
fields = ['headline', 'body', 'anchor', 'weight']
|
fields = ['headline', 'body', 'anchor', 'weight']
|
||||||
slug_field = 'anchor'
|
slug_field = 'anchor'
|
||||||
slug_url_kwarg = 'item_anchor'
|
slug_url_kwarg = 'item_anchor'
|
||||||
|
active_menu = 'info_categories'
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_team(self):
|
||||||
context = super().get_context_data(**kwargs)
|
return Team.objects.get(
|
||||||
context['team'] = self.team
|
camp__slug=self.kwargs['camp_slug'],
|
||||||
return context
|
slug=self.kwargs['team_slug']
|
||||||
|
)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
next = self.request.GET.get('next')
|
next = self.request.GET.get('next')
|
||||||
|
@ -49,11 +75,18 @@ class InfoItemUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibl
|
||||||
return self.team.get_absolute_url()
|
return self.team.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
class InfoItemDeleteView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, RevisionMixin, DeleteView):
|
class InfoItemDeleteView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, RevisionMixin, DeleteView):
|
||||||
model = InfoItem
|
model = InfoItem
|
||||||
template_name = "info_item_delete_confirm.html"
|
template_name = "team_info_item_delete_confirm.html"
|
||||||
slug_field = 'anchor'
|
slug_field = 'anchor'
|
||||||
slug_url_kwarg = 'item_anchor'
|
slug_url_kwarg = 'item_anchor'
|
||||||
|
active_menu = 'info_categories'
|
||||||
|
|
||||||
|
def get_team(self):
|
||||||
|
return Team.objects.get(
|
||||||
|
camp__slug=self.kwargs['camp_slug'],
|
||||||
|
slug=self.kwargs['team_slug']
|
||||||
|
)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
next = self.request.GET.get('next')
|
next = self.request.GET.get('next')
|
||||||
|
|
111
src/teams/views/members.py
Normal file
111
src/teams/views/members.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.views.generic import DetailView, UpdateView
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
|
from ..models import Team, TeamMember
|
||||||
|
from profiles.models import Profile
|
||||||
|
from camps.mixins import CampViewMixin
|
||||||
|
|
||||||
|
from .mixins import EnsureTeamMemberResponsibleMixin, TeamViewMixin
|
||||||
|
from ..email import add_added_membership_email, add_removed_membership_email
|
||||||
|
|
||||||
|
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TeamMembersView(CampViewMixin, DetailView):
|
||||||
|
template_name = "team_members.html"
|
||||||
|
context_object_name = 'team'
|
||||||
|
model = Team
|
||||||
|
slug_url_kwarg = 'team_slug'
|
||||||
|
active_menu = 'members'
|
||||||
|
|
||||||
|
|
||||||
|
class TeamJoinView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
|
template_name = "team_join.html"
|
||||||
|
model = Team
|
||||||
|
fields = []
|
||||||
|
slug_url_kwarg = 'team_slug'
|
||||||
|
active_menu = 'members'
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
if not Profile.objects.get(user=request.user).description:
|
||||||
|
messages.warning(
|
||||||
|
request,
|
||||||
|
"Please fill the description in your profile before joining a team"
|
||||||
|
)
|
||||||
|
return redirect('teams:list', camp_slug=self.camp.slug)
|
||||||
|
|
||||||
|
if request.user in self.get_object().members.all():
|
||||||
|
messages.warning(request, "You are already a member of this team")
|
||||||
|
return redirect('teams:list', camp_slug=self.camp.slug)
|
||||||
|
|
||||||
|
if not self.get_object().needs_members:
|
||||||
|
messages.warning(request, "This team does not need members right now")
|
||||||
|
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
||||||
|
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
TeamMember.objects.create(team=self.get_object(), user=self.request.user)
|
||||||
|
messages.success(self.request, "You request to join the team %s has been registered, thank you." % self.get_object().name)
|
||||||
|
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
||||||
|
|
||||||
|
|
||||||
|
class TeamLeaveView(LoginRequiredMixin, CampViewMixin, UpdateView):
|
||||||
|
template_name = "team_leave.html"
|
||||||
|
model = Team
|
||||||
|
fields = []
|
||||||
|
slug_url_kwarg = 'team_slug'
|
||||||
|
active_menu = 'members'
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
if request.user not in self.get_object().members.all():
|
||||||
|
messages.warning(request, "You are not a member of this team")
|
||||||
|
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
||||||
|
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
TeamMember.objects.filter(team=self.get_object(), user=self.request.user).delete()
|
||||||
|
messages.success(self.request, "You are no longer a member of the team %s" % self.get_object().name)
|
||||||
|
return redirect('teams:list', camp_slug=self.get_object().camp.slug)
|
||||||
|
|
||||||
|
|
||||||
|
class TeamMemberRemoveView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamMemberResponsibleMixin, UpdateView):
|
||||||
|
template_name = "teammember_remove.html"
|
||||||
|
model = TeamMember
|
||||||
|
fields = []
|
||||||
|
active_menu = 'members'
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.delete()
|
||||||
|
if add_removed_membership_email(form.instance):
|
||||||
|
messages.success(self.request, "Team member removed")
|
||||||
|
else:
|
||||||
|
messages.success(self.request, "Team member removed (unable to add email to outgoing queue).")
|
||||||
|
logger.error(
|
||||||
|
'Unable to add removed email to outgoing queue for teammember: {}'.format(form.instance)
|
||||||
|
)
|
||||||
|
return redirect('teams:general', camp_slug=self.camp.slug, team_slug=form.instance.team.slug)
|
||||||
|
|
||||||
|
|
||||||
|
class TeamMemberApproveView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamMemberResponsibleMixin, UpdateView):
|
||||||
|
template_name = "teammember_approve.html"
|
||||||
|
model = TeamMember
|
||||||
|
fields = []
|
||||||
|
active_menu = 'members'
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.instance.approved = True
|
||||||
|
form.instance.save()
|
||||||
|
if add_added_membership_email(form.instance):
|
||||||
|
messages.success(self.request, "Team member approved")
|
||||||
|
else:
|
||||||
|
messages.success(self.request, "Team member removed (unable to add email to outgoing queue).")
|
||||||
|
logger.error(
|
||||||
|
'Unable to add approved email to outgoing queue for teammember: {}'.format(form.instance)
|
||||||
|
)
|
||||||
|
return redirect('teams:general', camp_slug=self.camp.slug, team_slug=form.instance.team.slug)
|
|
@ -13,7 +13,7 @@ class EnsureTeamResponsibleMixin(object):
|
||||||
self.team = Team.objects.get(slug=kwargs['team_slug'], camp=self.camp)
|
self.team = Team.objects.get(slug=kwargs['team_slug'], camp=self.camp)
|
||||||
if request.user not in self.team.responsible_members.all():
|
if request.user not in self.team.responsible_members.all():
|
||||||
messages.error(request, 'No thanks')
|
messages.error(request, 'No thanks')
|
||||||
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=self.team.slug)
|
return redirect('teams:general', camp_slug=self.camp.slug, team_slug=self.team.slug)
|
||||||
|
|
||||||
return super().dispatch(
|
return super().dispatch(
|
||||||
request, *args, **kwargs
|
request, *args, **kwargs
|
||||||
|
@ -29,8 +29,19 @@ class EnsureTeamMemberResponsibleMixin(SingleObjectMixin):
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if request.user not in self.get_object().team.responsible_members.all():
|
if request.user not in self.get_object().team.responsible_members.all():
|
||||||
messages.error(request, 'No thanks')
|
messages.error(request, 'No thanks')
|
||||||
return redirect('teams:detail', camp_slug=self.get_object().team.camp.slug, team_slug=self.get_object().team.slug)
|
return redirect('teams:general', camp_slug=self.get_object().team.camp.slug, team_slug=self.get_object().team.slug)
|
||||||
|
|
||||||
return super().dispatch(
|
return super().dispatch(
|
||||||
request, *args, **kwargs
|
request, *args, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TeamViewMixin:
|
||||||
|
|
||||||
|
def get_team(self):
|
||||||
|
return self.get_object().team
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['team'] = self.get_team()
|
||||||
|
return context
|
||||||
|
|
|
@ -1,44 +1,74 @@
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.views.generic import DetailView, CreateView, UpdateView
|
from django.views.generic import DetailView, CreateView, UpdateView
|
||||||
|
from django import forms
|
||||||
|
|
||||||
from camps.mixins import CampViewMixin
|
from camps.mixins import CampViewMixin
|
||||||
from ..models import TeamTask
|
from ..models import Team, TeamTask
|
||||||
from .mixins import EnsureTeamResponsibleMixin
|
from .mixins import EnsureTeamResponsibleMixin, TeamViewMixin
|
||||||
|
|
||||||
|
|
||||||
class TaskDetailView(CampViewMixin, DetailView):
|
class TeamTasksView(CampViewMixin, DetailView):
|
||||||
|
template_name = "team_tasks.html"
|
||||||
|
context_object_name = 'team'
|
||||||
|
model = Team
|
||||||
|
slug_url_kwarg = 'team_slug'
|
||||||
|
active_menu = 'tasks'
|
||||||
|
|
||||||
|
|
||||||
|
class TaskDetailView(CampViewMixin, TeamViewMixin, DetailView):
|
||||||
template_name = "task_detail.html"
|
template_name = "task_detail.html"
|
||||||
context_object_name = "task"
|
context_object_name = "task"
|
||||||
model = TeamTask
|
model = TeamTask
|
||||||
|
active_menu = 'tasks'
|
||||||
|
|
||||||
|
|
||||||
class TaskCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, CreateView):
|
class TaskForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = TeamTask
|
||||||
|
fields = ['name', 'description', 'when', 'completed']
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.fields['when'].widget.widgets = [
|
||||||
|
forms.DateTimeInput(
|
||||||
|
attrs={"placeholder": "Start"}
|
||||||
|
),
|
||||||
|
forms.DateTimeInput(
|
||||||
|
attrs={"placeholder": "End"}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCreateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, CreateView):
|
||||||
model = TeamTask
|
model = TeamTask
|
||||||
template_name = "task_form.html"
|
template_name = "task_form.html"
|
||||||
fields = ['name', 'description', 'when', 'completed']
|
form_class = TaskForm
|
||||||
|
active_menu = 'tasks'
|
||||||
def get_context_data(self, *args, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
def get_team(self):
|
||||||
context['team'] = self.team
|
return Team.objects.get(
|
||||||
return context
|
camp__slug=self.kwargs['camp_slug'],
|
||||||
|
slug=self.kwargs['team_slug']
|
||||||
def form_valid(self, form):
|
)
|
||||||
task = form.save(commit=False)
|
|
||||||
task.team = self.team
|
def form_valid(self, form):
|
||||||
if not task.name:
|
task = form.save(commit=False)
|
||||||
task.name = "noname"
|
task.team = self.team
|
||||||
task.save()
|
if not task.name:
|
||||||
return HttpResponseRedirect(task.get_absolute_url())
|
task.name = "noname"
|
||||||
|
task.save()
|
||||||
def get_success_url(self):
|
return HttpResponseRedirect(task.get_absolute_url())
|
||||||
return self.get_object().get_absolute_url()
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return self.get_object().get_absolute_url()
|
||||||
class TaskUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, UpdateView):
|
|
||||||
model = TeamTask
|
|
||||||
template_name = "task_form.html"
|
class TaskUpdateView(LoginRequiredMixin, CampViewMixin, TeamViewMixin, EnsureTeamResponsibleMixin, UpdateView):
|
||||||
fields = ['name', 'description', 'when', 'completed']
|
model = TeamTask
|
||||||
|
template_name = "task_form.html"
|
||||||
|
form_class = TaskForm
|
||||||
|
active_menu = 'tasks'
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_context_data(self, *args, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="top-navbar" class="navbar-collapse collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li><a href="{% url 'news:index' %}">News</a></li>
|
<li><a href="{% url 'news:index' %}">News</a></li>
|
||||||
<li><a href="{% url 'shop:index' %}">Shop</a></li>
|
<li><a href="{% url 'shop:index' %}">Shop</a></li>
|
||||||
|
|
Loading…
Reference in a new issue