Repository navigation
Expand file tree
/
Copy pathtags.py
More file actions
168 lines (137 loc) · 5.71 KB
/
Copy pathtags.py
File metadata and controls
168 lines (137 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db import transaction
from django.db.models import Count
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from bookmarks.forms import TagForm, TagMergeForm
from bookmarks.models import Bookmark, Tag
from bookmarks.type_defs import HttpRequest
from bookmarks.utils import redirect_with_query
from bookmarks.views import turbo
@login_required
def tags_index(request: HttpRequest):
if request.method == "POST" and "delete_tag" in request.POST:
tag_id = request.POST.get("delete_tag")
tag = get_object_or_404(Tag, id=tag_id, owner=request.user)
tag.delete()
return redirect_with_query(request, reverse("linkding:tags.index"))
search = request.GET.get("search", "").strip()
unused_only = request.GET.get("unused", "") == "true"
sort = request.GET.get("sort", "name-asc")
tags_queryset = Tag.objects.filter(owner=request.user).annotate(
bookmark_count=Count("bookmark")
)
if sort == "name-desc":
tags_queryset = tags_queryset.order_by("-name")
elif sort == "count-asc":
tags_queryset = tags_queryset.order_by("bookmark_count", "name")
elif sort == "count-desc":
tags_queryset = tags_queryset.order_by("-bookmark_count", "name")
else: # Default: name-asc
tags_queryset = tags_queryset.order_by("name")
total_tags = tags_queryset.count()
if search:
tags_queryset = tags_queryset.filter(name__icontains=search)
if unused_only:
tags_queryset = tags_queryset.filter(bookmark_count=0)
paginator = Paginator(tags_queryset, 50)
page_number = request.GET.get("page")
page = paginator.get_page(page_number)
context = {
"page": page,
"search": search,
"unused_only": unused_only,
"sort": sort,
"total_tags": total_tags,
}
return render(request, "tags/index.html", context)
@login_required
def tag_new(request: HttpRequest):
form_data = request.POST if request.method == "POST" else None
form = TagForm(user=request.user, data=form_data)
if request.method == "POST":
if form.is_valid():
tag = form.save()
messages.success(request, f'Tag "{tag.name}" created successfully.')
return HttpResponseRedirect(reverse("linkding:tags.index"))
else:
return turbo.stream(
turbo.replace(
request,
"tag-modal",
"tags/new.html",
{"form": form},
method="morph",
)
)
return render(request, "tags/new.html", {"form": form})
@login_required
def tag_edit(request: HttpRequest, tag_id: int):
tag = get_object_or_404(Tag, id=tag_id, owner=request.user)
form_data = request.POST if request.method == "POST" else None
form = TagForm(user=request.user, data=form_data, instance=tag)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect_with_query(request, reverse("linkding:tags.index"))
else:
return turbo.stream(
turbo.replace(
request,
"tag-modal",
"tags/edit.html",
{"tag": tag, "form": form},
method="morph",
)
)
return render(request, "tags/edit.html", {"tag": tag, "form": form})
@login_required
def tag_merge(request: HttpRequest):
form_data = request.POST if request.method == "POST" else None
form = TagMergeForm(user=request.user, data=form_data)
if request.method == "POST":
if form.is_valid():
target_tag = form.cleaned_data["target_tag"]
merge_tags = form.cleaned_data["merge_tags"]
with transaction.atomic():
BookmarkTag = Bookmark.tags.through
# Get all bookmarks that have any of the merge tags, but do not
# already have the target tag
bookmark_ids = list(
Bookmark.objects.filter(tags__in=merge_tags)
.exclude(tags=target_tag)
.values_list("id", flat=True)
.distinct()
)
# Create new relationships to the target tag
new_relationships = [
BookmarkTag(tag_id=target_tag.id, bookmark_id=bookmark_id)
for bookmark_id in bookmark_ids
]
if new_relationships:
BookmarkTag.objects.bulk_create(new_relationships)
# Bulk delete all relationships for merge tags
merge_tag_ids = [tag.id for tag in merge_tags]
BookmarkTag.objects.filter(tag_id__in=merge_tag_ids).delete()
# Delete the merged tags
tag_names = [tag.name for tag in merge_tags]
Tag.objects.filter(id__in=merge_tag_ids).delete()
messages.success(
request,
f'Successfully merged {len(merge_tags)} tags ({", ".join(tag_names)}) into "{target_tag.name}".',
)
return HttpResponseRedirect(reverse("linkding:tags.index"))
else:
return turbo.stream(
turbo.replace(
request,
"tag-modal",
"tags/merge.html",
{"form": form},
method="morph",
)
)
return render(request, "tags/merge.html", {"form": form})
<
2C59
/div>