diff --git a/hc/accounts/admin.py b/hc/accounts/admin.py index 5f081b0b..43f384c6 100644 --- a/hc/accounts/admin.py +++ b/hc/accounts/admin.py @@ -107,6 +107,7 @@ class ProfileAdmin(admin.ModelAdmin): @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): + readonly_fields = ("code", "owner") list_select_related = ("owner", ) list_display = ("id", "name_", "users", "engagement", "switch") diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 3b3cafe6..d236b0bf 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -202,7 +202,7 @@ class Profile(models.Model): class Project(models.Model): - code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + code = models.UUIDField(default=uuid.uuid4, unique=True) name = models.CharField(max_length=200, blank=True) owner = models.ForeignKey(User, models.CASCADE) api_key = models.CharField(max_length=128, blank=True) diff --git a/hc/accounts/views.py b/hc/accounts/views.py index fa1346cf..ea4c8eb7 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -183,6 +183,7 @@ def profile(request): ctx = { "page": "profile", "profile": profile, + "my_projects_status": "default" } if request.method == "POST": @@ -192,16 +193,50 @@ def profile(request): elif "set_password" in request.POST: profile.send_set_password_link() return redirect("hc-link-sent") + elif "leave_project" in request.POST: + code = request.POST["code"] + try: + project = Project.objects.get(code=code, + member__user=request.user) + except Project.DoesNotExist: + return HttpResponseBadRequest() + if profile.current_project == project: + profile.current_project = None + profile.save() + + Member.objects.filter(project=project, user=request.user).delete() + + ctx["left_project"] = project + ctx["my_projects_status"] = "info" + + # Retrieve projects right before rendering the template-- + # The list of the projects might have *just* changed + ctx["projects"] = list(profile.projects()) return render(request, "accounts/profile.html", ctx) +@login_required +@require_POST +def add_project(request): + form = ProjectNameForm(request.POST) + if not form.is_valid(): + return HttpResponseBadRequest() + + project = Project(owner=request.user) + project.code = project.badge_key = str(uuid.uuid4()) + project.name = form.cleaned_data["name"] + project.save() + + return redirect("hc-switch-project", project.code) + + @login_required def project(request, code): project = Project.objects.get(code=code, owner_id=request.user.id) ctx = { - "page": "profile", + "page": "project", "project": project, "show_api_keys": False, "project_name_status": "default", @@ -460,3 +495,11 @@ def close(request): request.session.flush() return redirect("hc-index") + + +@require_POST +@login_required +def remove_project(request, code): + project = Project.objects.get(code=code, owner=request.user) + project.delete() + return redirect("hc-profile") diff --git a/hc/front/views.py b/hc/front/views.py index 27a47ddb..5394f0c1 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -7,7 +7,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core import signing -from django.db.models import Count, Q +from django.db.models import Count from django.http import (Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, JsonResponse) from django.shortcuts import get_object_or_404, redirect, render @@ -17,7 +17,6 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST -from hc.accounts.models import Project from hc.api.models import (DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check, Ping, Notification) from hc.api.transports import Telegram diff --git a/hc/urls.py b/hc/urls.py index 219600e6..a9bce525 100644 --- a/hc/urls.py +++ b/hc/urls.py @@ -7,7 +7,9 @@ urlpatterns = [ path('admin/login/', accounts_views.login), path('admin/', admin.site.urls), path('accounts/', include('hc.accounts.urls')), + path('projects/add/', accounts_views.add_project, name="hc-add-project"), path('projects//settings/', accounts_views.project, name="hc-project-settings"), + path('projects//remove/', accounts_views.remove_project, name="hc-remove-project"), path('', include('hc.api.urls')), path('', include('hc.front.urls')), path('', include('hc.payments.urls')) diff --git a/static/css/profile.css b/static/css/profile.css index 3252afc6..c551311d 100644 --- a/static/css/profile.css +++ b/static/css/profile.css @@ -45,4 +45,24 @@ span.loading { font-size: 12px; border-radius: 2px; padding: 2px 6px; -} \ No newline at end of file +} + +#my-projects th { + border-top: 0; +} + +#my-projects td { + vertical-align: middle; +} + +#my-projects .num-checks { + +} + +#my-projects .name { + width: 200px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + diff --git a/static/css/settings.css b/static/css/settings.css index fce8acb9..7172b16c 100644 --- a/static/css/settings.css +++ b/static/css/settings.css @@ -15,13 +15,13 @@ color: #5cb85c; } -#close-account { +#close-account, #remove-project { margin-left: 24px; border-color: #d43f3a; color: #d43f3a; } -#close-account:hover { +#close-account:hover, #remove-project:hover { background-color: #ffebea; } diff --git a/static/js/profile.js b/static/js/profile.js new file mode 100644 index 00000000..374ff07d --- /dev/null +++ b/static/js/profile.js @@ -0,0 +1,13 @@ +$(function() { + + $(".leave-project").click(function() { + var $this = $(this); + + $("#leave-project-name").text($this.data("name")); + $("#leave-project-code").val($this.data("code")); + $('#leave-project-modal').modal("show"); + + return false; + }); + +}); \ No newline at end of file diff --git a/templates/accounts/billing.html b/templates/accounts/billing.html index ae197cae..23d6f724 100644 --- a/templates/accounts/billing.html +++ b/templates/accounts/billing.html @@ -180,7 +180,7 @@ @@ -80,12 +145,12 @@ @@ -159,7 +174,7 @@