diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..32af6a1 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,16 @@ +version: '3.8' +services: + db: + image: postgres:16.1-alpine3.19 + restart: always + environment: + POSTGRES_HOST_AUTH_METHOD: trust +# POSTGRES_USER: postgres +# POSTGRES_PASSWORD: postgres +# POSTGRES_DB: postgres + ports: + - "5900:5432" + redis: + image: redis:alpine3.17 + ports: + - "6379:6379" diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index bb00d3e..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: "3.8" -services: - db: - image: postgres:15-alpine - environment: - - POSTGRES_HOST_AUTH_METHOD=trust - ports: - - "5432:5432" - redis: - image: redis:alpine3.17 - ports: - - "6379:6379" diff --git a/gary/settings.py b/gary/settings.py index bfc8f78..bdc121f 100644 --- a/gary/settings.py +++ b/gary/settings.py @@ -173,6 +173,7 @@ def get_envvar_list(envvar_name, default=[], separator=",", normalize=True): ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_AUTHENTICATION_METHOD = 'email' +ACCOUNT_USER_DISPLAY = "gifter.utils.user_display" AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", diff --git a/gifter/migrations/0006_wishlist_groups.py b/gifter/migrations/0006_wishlist_groups.py new file mode 100644 index 0000000..cbcde29 --- /dev/null +++ b/gifter/migrations/0006_wishlist_groups.py @@ -0,0 +1,29 @@ +# Generated by Django 4.1.2 on 2023-12-17 02:04 + +from django.db import migrations, models + + +def forwards_func(apps, schema_editor): + Wishlist = apps.get_model("gifter", "Wishlist") + for wishlist in Wishlist.objects.all(): + wishlist.groups.add(wishlist.group) + wishlist.save() + + +class Migration(migrations.Migration): + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ("gifter", "0005_alter_claim_options_alter_groupinvitation_options_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="wishlist", + name="groups", + field=models.ManyToManyField(related_name="wishlists", to="auth.group"), + ), + migrations.RunPython( + code=forwards_func, + reverse_code=migrations.RunPython.noop, + ), + ] diff --git a/gifter/migrations/0007_remove_wishlist_group.py b/gifter/migrations/0007_remove_wishlist_group.py new file mode 100644 index 0000000..6881be7 --- /dev/null +++ b/gifter/migrations/0007_remove_wishlist_group.py @@ -0,0 +1,16 @@ +# Generated by Django 4.1.2 on 2023-12-17 02:29 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("gifter", "0006_wishlist_groups"), + ] + + operations = [ + migrations.RemoveField( + model_name="wishlist", + name="group", + ), + ] diff --git a/gifter/models.py b/gifter/models.py index 18957d8..8d33f3c 100644 --- a/gifter/models.py +++ b/gifter/models.py @@ -87,10 +87,10 @@ def __str__(self): class Wishlist(CommonBaseClass): title = models.CharField(max_length=120, blank=False, null=False) owner = models.ForeignKey(User, on_delete=models.CASCADE) - group = models.ForeignKey(Group, on_delete=models.CASCADE) + groups = models.ManyToManyField(Group, related_name="wishlists") def __str__(self): - return f"Wishlist for {self.owner} on {self.group.name}" + return f"Wishlist for {self.owner} (in {self.groups.count()} groups)" class Item(CommonBaseClass): diff --git a/gifter/static/css/main.css b/gifter/static/css/main.css index f727dd8..deb47f3 100644 --- a/gifter/static/css/main.css +++ b/gifter/static/css/main.css @@ -30,12 +30,14 @@ a:link, a:visited { .profile { display: flex; align-items: center; + justify-content: center; } .profile-photo { max-height: 40px; max-width: 40px; border-radius: 100px; + margin-right: 0.5em; } .socialaccount_providers { diff --git a/gifter/urls.py b/gifter/urls.py index 75818ea..3d05752 100644 --- a/gifter/urls.py +++ b/gifter/urls.py @@ -22,7 +22,7 @@ GroupDeleteView, SendInviteFormView, MyWishlistsListView, - ItemDeleteView, + ItemDeleteView, UpdateWishlistOptionsView, ClaimListView, ) urlpatterns = [ @@ -41,6 +41,11 @@ path( "groups//wishlists/", WishlistDetailView.as_view(), + name="wishlist_detail_with_group", + ), + path( + "wishlists/", + WishlistDetailView.as_view(), name="wishlist_detail", ), path( @@ -49,10 +54,15 @@ name="wishlist_update", ), path( - "groups//wishlists//delete", + "wishlists//delete", WishlistDeleteView.as_view(), name="wishlist_delete", ), + path( + "groups//wishlists//delete", + WishlistDeleteView.as_view(), + name="wishlist_delete_with_group", + ), path("wishlists", MyWishlistsListView.as_view(), name="my_wishlists"), path( "wishlists//items/create", @@ -74,6 +84,16 @@ ClaimCreateView.as_view(), name="claim_create", ), + path( + "wishlists//items//claims", + ClaimListView.as_view(), + name="claim_list", + ), + path( + "groups//wishlists//items//claims", + ClaimListView.as_view(), + name="claim_list_with_group", + ), path( "wishlists//items//claims/", ClaimUpdateView.as_view(), @@ -84,6 +104,14 @@ ClaimDeleteView.as_view(), name="claim_delete", ), + path( + "wishlists//add-to-group", + UpdateWishlistOptionsView.as_view(), + name="add_wishlist_to_group"), + path( + "wishlists//remove-from-group", + UpdateWishlistOptionsView.as_view(), + name="remove_wishlist_from_group"), path( "invitations/incoming/", incoming_invitation, diff --git a/gifter/utils.py b/gifter/utils.py new file mode 100644 index 0000000..a868696 --- /dev/null +++ b/gifter/utils.py @@ -0,0 +1,7 @@ + + +def user_display(user): + if user.first_name or user.last_name: + return f"{user.first_name} {user.last_name}" + else: + return user.email diff --git a/gifter/views.py b/gifter/views.py index 3d9112e..06085da 100644 --- a/gifter/views.py +++ b/gifter/views.py @@ -7,7 +7,9 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import Group from django.core.exceptions import ValidationError -from django.http import HttpResponse +from django.db import transaction +from django.db.models import Q +from django.http import HttpResponse, HttpRequest from django.shortcuts import redirect from django.template.defaultfilters import pluralize from django.urls import reverse @@ -98,6 +100,9 @@ class GroupDetailView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = super(GroupDetailView, self).get_context_data(**kwargs) context["send_invite_form"] = InviteParticipantForm(self.request.GET) + context["pending_invites"] = GroupInvitation.objects.filter( + ~Q(destination_email__in=[self.object.user_set.all().values_list("email", flat=True)]), target_group=self.object, verified_at__isnull=True, + ) return context @@ -121,6 +126,10 @@ def get_context_data(self, **kwargs): context["my_claims"] = Claim.objects.filter( owner=me, item__wishlist=self.object.id ) + context["group_pk"] = self.kwargs.get("group_pk") + context["group_name"] = self.object.groups.get( + id=context["group_pk"] + ) if context["group_pk"] else None return context @@ -149,15 +158,29 @@ def get_initial(self): } def get_success_url(self): + group_pk = self.kwargs.get("group_pk") + if group_pk: + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.id), + }, + ) return reverse( "wishlist_detail", - kwargs={"group_pk": str(self.object.group.id), "pk": str(self.object.id)}, + kwargs={ + "pk": str(self.object.id), + }, ) def form_valid(self, form): - user = self.request.user - form.instance.owner = user - form.instance.group_id = self.request.resolver_match.kwargs["group_pk"] + with transaction.atomic(): + user = self.request.user + form.instance.owner = user + form.instance.save() + group_pk = self.request.resolver_match.kwargs["group_pk"] + form.instance.groups.add(group_pk) return super(WishlistCreateView, self).form_valid(form) @@ -188,11 +211,17 @@ class WishlistDeleteView(LoginRequiredMixin, DeleteView): template_name = "gifter/wishlist_confirm_delete.html" def get_success_url(self): + group_pk = self.kwargs.get("group_pk") + if group_pk: + return reverse( + "group_detail", + kwargs={ + "pk": group_pk, + }, + ) + return reverse( - "group_detail", - kwargs={ - "pk": self.object.group.id, - }, + "my_wishlists" ) @@ -207,11 +236,18 @@ def get_context_data(self, **kwargs): return context def get_success_url(self): + if group_pk := self.kwargs.get("group_pk"): + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": str(self.object.wishlist.id), - "group_pk": self.object.wishlist.group_id, }, ) @@ -239,11 +275,18 @@ def get_context_data(self, **kwargs): return context def get_success_url(self): + if group_pk := self.kwargs.get("group_pk"): + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": str(self.object.wishlist.id), - "group_pk": self.object.wishlist.group_id, }, ) @@ -253,11 +296,18 @@ class ItemDeleteView(LoginRequiredMixin, DeleteView): template_name = "gifter/item_confirm_delete.html" def get_success_url(self): + if group_pk := self.kwargs.get("group_pk"): + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": self.object.wishlist.id, - "group_pk": self.object.wishlist.group_id, }, ) @@ -276,11 +326,19 @@ def get_context_data(self, **kwargs): return context def get_success_url(self): + group_pk = self.kwargs.get("group_pk") + if group_pk: + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.item.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": str(self.object.item.wishlist.id), - "group_pk": self.object.item.wishlist.group_id, }, ) @@ -308,24 +366,58 @@ def get_context_data(self, **kwargs): return context def get_success_url(self): + if group_pk := self.kwargs.get("group_pk"): + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.item.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": str(self.object.item.wishlist.id), - "group_pk": self.object.item.wishlist.group_id, }, ) +class ClaimListView(LoginRequiredMixin, ListView): + model = Claim + template_name = "gifter/claim_list.html" + + def get_queryset(self): + return Claim.objects.filter(item=self.kwargs["item_pk"]) + + def get_context_data(self, *, object_list=None, **kwargs): + context = super().get_context_data(**kwargs) + group_pk = self.kwargs.get("group_pk") + context["group_pk"] = group_pk + if group_pk: + context["group"] = Group.objects.get( + id=group_pk + ) if group_pk else None + context["item"] = Item.objects.get(id=self.kwargs["item_pk"]) + context["wishlist"] = Wishlist.objects.get(id=self.kwargs["wishlist_pk"]) + return context + + class ClaimDeleteView(LoginRequiredMixin, DeleteView): model = Claim def get_success_url(self): + if group_pk := self.kwargs.get("group_pk"): + return reverse( + "wishlist_detail_with_group", + kwargs={ + "group_pk": group_pk, + "pk": str(self.object.item.wishlist.id), + }, + ) return reverse( "wishlist_detail", kwargs={ "pk": str(self.object.item.wishlist.id), - "group_pk": self.object.item.wishlist.group_id, }, ) @@ -436,3 +528,42 @@ def form_valid(self, form): ) return super().form_valid(form) + + +class UpdateWishlistOptionsView(LoginRequiredMixin, TemplateView): + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["wishlist"] = Wishlist.objects.get(id=self.kwargs["pk"]) + return context + + def post(self, request: HttpRequest, *args, **kwargs): + wishlist = Wishlist.objects.get(id=self.kwargs["pk"]) + if request.POST.get("action") == "add_wishlist_to_group": + wishlist.groups.add(request.POST.get("group_pk")) + messages.add_message( + request, + level=messages.SUCCESS, + message=f"Successfully added wishlist to group", + fail_silently=True, + ) + elif request.POST.get("action") == "remove_wishlist_from_group": + wishlist.groups.remove(request.POST.get("group_pk")) + messages.add_message( + request, + level=messages.SUCCESS, + message=f"Successfully removed wishlist from group", + fail_silently=True, + ) + + if next_url := request.POST.get("next"): + return redirect(to=next_url) + + return redirect( + to=reverse( + "wishlist_detail", + kwargs={ + "pk": str(wishlist.id), + }, + ) + ) diff --git a/justfile b/justfile new file mode 100644 index 0000000..f343a25 --- /dev/null +++ b/justfile @@ -0,0 +1,4 @@ + +db: + docker compose down || true + docker compose up -d diff --git a/templates/account/base.html b/templates/account/base.html index c84c33a..5f2e66a 100644 --- a/templates/account/base.html +++ b/templates/account/base.html @@ -48,16 +48,15 @@ {% block outside_container %}
-
+
{% bootstrap_messages %}
-
+
-
- {% block content %} - {% endblock %} +
+ {% block content %}{% endblock %}
diff --git a/templates/account/email.html b/templates/account/email.html new file mode 100644 index 0000000..344212a --- /dev/null +++ b/templates/account/email.html @@ -0,0 +1,81 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block title %}{% trans "Account - E-mail" %}{% endblock %} + +{% block content %} +

{% trans "E-mail Addresses" %}

+ {% if user.emailaddress_set.all %} +
+
{% trans 'The following e-mail addresses are associated with your account:' %}
+
+ + +
+
+ {% else %} +

{% trans 'Warning:'%} {% trans "There aren't any email addresses associated with your account. Please add one to receive updates and important communications." %}

+ {% endif %} +
+
+
{% trans "Add E-mail Address" %}
+
+ +

Want a different email address associated with your account? Add that email here:

+ +
+ {% csrf_token %} + {{ form.as_p }} + +
+
+
+{% endblock %} + + +{% block extra_body %} + +{% endblock %} diff --git a/templates/account/email_confirm.html b/templates/account/email_confirm.html new file mode 100644 index 0000000..6e5c0b0 --- /dev/null +++ b/templates/account/email_confirm.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Confirm E-mail Address" %}{% endblock %} + +{% block content %} +
+
{% trans "Confirm E-mail Address" %}
+
+ {% if confirmation %} + {% user_display confirmation.email_address.user as user_display %} +

{% blocktrans with email=confirmation.email_address.email full_name=confirmation.email_address.user.get_full_name %}Please confirm that {{ email }} is a valid e-mail address for {{ full_name }}.{% endblocktrans %}

+ +
+ {% csrf_token %} + +
+ {% else %} + {% url 'account_email' as email_url %} +

{% blocktrans %}This e-mail confirmation link expired or is invalid.{% endblocktrans %}

+

{% blocktrans %}Please issue a new e-mail confirmation request.{% endblocktrans %}

+ {% endif %} +
+
+ +{% endblock %} diff --git a/templates/account/login.html b/templates/account/login.html index 750a07f..8d62386 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -13,23 +13,19 @@
{% trans "Sign In" %}
{% get_providers as socialaccount_providers %} - {% if socialaccount_providers %} -

{% blocktrans with site.name as site_name %}Please sign in with one - of your existing accounts or sign up - for an account.{% endblocktrans %}

-
    {% include "socialaccount/snippets/provider_list.html" with process="login" %}
{% include "socialaccount/snippets/login_extra.html" %} - {% else %} -

{% blocktrans %}If you have not created an account yet, then please - sign up first.{% endblocktrans %}

{% endif %} +
+ {% blocktrans %} +

First time here? Sign Up

+ {% endblocktrans %} {% csrf_token %} {% bootstrap_form form %} {% if redirect_field_value %} diff --git a/templates/account/password_change.html b/templates/account/password_change.html new file mode 100644 index 0000000..326dd9a --- /dev/null +++ b/templates/account/password_change.html @@ -0,0 +1,21 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Change Password" %}{% endblock %} + +{% block content %} +
+
+
Change Password
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/templates/account/password_reset.html b/templates/account/password_reset.html new file mode 100644 index 0000000..d95a363 --- /dev/null +++ b/templates/account/password_reset.html @@ -0,0 +1,24 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Password Reset" %}{% endblock %} + +{% block content %} +
+
+
Reset your password
+ +

We'll send you an e-mail with instructions to reset your password.

+

If you don't receive an e-mail, please make sure you've entered the address you were registered with, and check your spam folder.

+
+
+{% endblock %} diff --git a/templates/account/password_reset_done.html b/templates/account/password_reset_done.html new file mode 100644 index 0000000..3ba4491 --- /dev/null +++ b/templates/account/password_reset_done.html @@ -0,0 +1,28 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Password Reset" %}{% endblock %} + +{% block content %} +
+
+
Password Reset Sent
+
+ {% if user.is_authenticated %} +

+ {% include "account/snippets/already_logged_in.html" %} +

+ {% endif %} +

We sent you a password reset e-mail!

+

+ If you don't receive an e-mail, please make sure you've entered the address you were registered + with, + and check your spam folder. +

+
+
+
+{% endblock %} diff --git a/templates/account/password_reset_from_key.html b/templates/account/password_reset_from_key.html new file mode 100644 index 0000000..c52d72b --- /dev/null +++ b/templates/account/password_reset_from_key.html @@ -0,0 +1,38 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Change Password" %}{% endblock %} + +{% block content %} + {% if token_fail %} +
+
+
Invalid Reset Link
+ {% url 'account_reset_password' as passwd_reset_url %} +

The password reset link was invalid, possibly because it has already been used. + Please request a new password reset.

+
+
+ {% else %} +
+
+
Change Password
+ +
+
+
+ {% endif %} +{% endblock %} diff --git a/templates/account/password_reset_from_key_done.html b/templates/account/password_reset_from_key_done.html new file mode 100644 index 0000000..7918394 --- /dev/null +++ b/templates/account/password_reset_from_key_done.html @@ -0,0 +1,17 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Change Password" %}{% endblock %} + +{% block content %} +
+
+
{% trans "Change Password" %}
+

{% trans 'Your password is now changed.' %}

+ Sign In +
+
+{% endblock %} diff --git a/templates/account/password_set.html b/templates/account/password_set.html new file mode 100644 index 0000000..3be0149 --- /dev/null +++ b/templates/account/password_set.html @@ -0,0 +1,20 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} + +{% load i18n %} +{% load account %} + +{% block title %}{% trans "Set Password" %}{% endblock %} + +{% block content %} +
+
{% trans "Set Password" %}
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + +
+
+
+{% endblock %} diff --git a/templates/account/profile.html b/templates/account/profile.html index 579bbf1..c5a474c 100644 --- a/templates/account/profile.html +++ b/templates/account/profile.html @@ -1,20 +1,19 @@ {% extends "account/base.html" %} {% block head_title %}Profile{% endblock %} {% block content %} - -
-
- Profile Photo of {{ request.user.display_name }} -
-
-
-
+
+
+

Profile

+
+
+ Profile Photo of {{ request.user.display_name }}

Name: {{ request.user.display_name }}

{% if request.user.display_email %} -

Email: {{ request.user.display_email }}

+

Email: {{ request.user.display_email }}

{% else %} -

No known email.

+

No known email.

{% endif %}
-{% endblock %}ยป \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/templates/account/signup.html b/templates/account/signup.html new file mode 100644 index 0000000..9aad05a --- /dev/null +++ b/templates/account/signup.html @@ -0,0 +1,37 @@ +{% extends "account/base.html" %} +{% load bootstrap5 %} +{% load i18n %} +{% load account socialaccount %} + +{% block head_title %}{% trans "Signup" %}{% endblock %} + +{% block content %} +
+
+ +
+
+{% endblock %} diff --git a/templates/base.html b/templates/base.html index 6f5128b..86d6705 100644 --- a/templates/base.html +++ b/templates/base.html @@ -9,7 +9,7 @@ Gary The Christmas Wishlist Fairy | {% block head_title %}Home{% endblock %} {% block styles %} - + {% endblock %} diff --git a/templates/gifter/claim_list.html b/templates/gifter/claim_list.html new file mode 100644 index 0000000..f88fa62 --- /dev/null +++ b/templates/gifter/claim_list.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} +{% block head_title %}Claims for {{ item.title }}{% endblock %} +{% block content %} + +

Claims for {{ item.title }}

+

The following users have claimed this item:

+ {% for claim in claim_list %} +
+
+

+ {{ claim.owner.display_name }} +

+
+
+ {% if claim.description %} + {{ claim.description }} + {% else %} + No description + {% endif %} +
+
+ {% endfor %} +{% endblock %} diff --git a/templates/gifter/group_detail.html b/templates/gifter/group_detail.html index 45d359d..0cb6971 100644 --- a/templates/gifter/group_detail.html +++ b/templates/gifter/group_detail.html @@ -8,8 +8,6 @@ -
-

{{ group.name }}

@@ -21,6 +19,11 @@
{{ user }} Profile Picture
+ {% endfor %} + {% for pending_invite in pending_invites %} +
+ {{ pending_invite.email_address }} Profile Picture +
{% endfor %}
- {% for wl in group.wishlist_set.all %} + {% for wl in group.wishlists.all %} {% endfor %} diff --git a/templates/gifter/item_form.html b/templates/gifter/item_form.html index bdfe1f1..bf389db 100644 --- a/templates/gifter/item_form.html +++ b/templates/gifter/item_form.html @@ -4,7 +4,8 @@ {% if request.user == wishlist.owner %}

Adding to my wishlist

{% else %} -

Suggesting for {{ wishlist.owner }}'s wishlist "{{ wishlist.title }}"

+

Adding an item "{{ wishlist.title }}"

+

{{ wishlist.owner }} will not be able to see this item.

{% endif %} {% if object %}
diff --git a/templates/gifter/wishlist_detail.html b/templates/gifter/wishlist_detail.html index 0572d20..d963e03 100644 --- a/templates/gifter/wishlist_detail.html +++ b/templates/gifter/wishlist_detail.html @@ -3,15 +3,18 @@ {% block head_title %}{{ wishlist.group.name }} | Wishlists{% endblock %} {% block content %}
-
- -
+
+ +
@@ -20,15 +23,22 @@

{{ wishlist.title }}

{% if request.user == wishlist.owner %} - Delete - Add Item   + {% if group_pk %} + Delete + {% else %} + Delete + {% endif %} + Add Item +   {% else %} - Suggest Item   + Add + Item   {% endif %}
- {% for wli in wishlist.item_set.all %} + {% for wli in wishlist.item_set.all %}{% if wishlist.owner != request.user or wli.owner == request.user %}{# Show if this isn't my list, or, if it is my list, then only show items I added. #}
@@ -41,29 +51,27 @@

{{ wishlist.title }}

{% if my_claims|has_intersection:wli.claim_set.all %} {% for claim in my_claims %} {% if claim.item == wli %} - - Update Claim   - {% if wli.claim_set.count %} - - {{ wli.claim_set.count }} - - Claims on this item - {% endif %} - + {% endif %} {% endfor %} {% else %} - - Claim   - {% if wli.claim_set.count %} - - {{ wli.claim_set.count }} - - Claims on this item - {% endif %} - + {% endif %} {% endif %} @@ -74,16 +82,70 @@

{{ wishlist.title }}


Links:
    - {% for link in wli.links %}
  • {{ link }}
  • {% endfor %} + {% for link in wli.links %} +
  • {{ link }}
  • {% endfor %}
{% endif %}
- {% endfor %} + {% endif %}{% endfor %} +
+
+
+
+ {% if request.user == wishlist.owner %} +
+
+
+
+

Appears in

+
+
+ {% if wishlist.groups.count %} +
    + {% for group in wishlist.groups.all %} +
  • + + + + {% csrf_token %} + {{ group.name }} + + +
  • + {% endfor %} +
+ {% else %} +

This wishlist does not appear in any groups! Add it to a group to share it with others.

+ {% endif %} +
+
+ {% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/gifter/wishlist_list.html b/templates/gifter/wishlist_list.html index cf2b969..d8d987b 100644 --- a/templates/gifter/wishlist_list.html +++ b/templates/gifter/wishlist_list.html @@ -5,7 +5,16 @@

My Wishlists

{% for wishlist in object_list %}
- {{ wishlist.group.name }} - {{ wishlist.title }} + {{ wishlist.title }} - + {% if wishlist.groups.count == 0 %} + Not shared + {% endif %} + {% if wishlist.groups.count == 1 %} + Shared in {{ wishlist.groups.first.name }} + {% endif %} + {% if wishlist.groups.count > 1 %} + Shared in {{ wishlist.groups.count }} groups + {% endif %}
{% endfor %}