minor changes
This commit is contained in:
@@ -704,6 +704,70 @@ class UGCPermissionTests(UGCMediaTestCase, UGCGatedTestCase):
|
|||||||
# Manual species tag applied.
|
# Manual species tag applied.
|
||||||
self.assertTrue(TagList.objects.filter(project=self.project, tag__name='dragon').exists())
|
self.assertTrue(TagList.objects.filter(project=self.project, tag__name='dragon').exists())
|
||||||
|
|
||||||
|
def _add_manual_creator_tag(self, name='lizo'):
|
||||||
|
creator_cat = TagCategory.objects.get(slug='creator')
|
||||||
|
tag, _ = Tag.objects.get_or_create(name=name, category=creator_cat, created_by=self.alice)
|
||||||
|
TagList.objects.create(project=self.project, tag=tag, added_by=self.alice)
|
||||||
|
return tag
|
||||||
|
|
||||||
|
def test_edit_shows_manual_creator_tag(self):
|
||||||
|
self.project.sync_creator_tags()
|
||||||
|
self._add_manual_creator_tag('lizo')
|
||||||
|
self.gate()
|
||||||
|
self.client.login(username='Alice', password='pw')
|
||||||
|
resp = self.client.get(reverse('library:project_edit', args=['test-pack']))
|
||||||
|
# The manual creator tag (no matching account) is serialized into the editor.
|
||||||
|
self.assertContains(resp, 'creator:lizo')
|
||||||
|
|
||||||
|
def test_edit_hides_account_backed_creator_tags(self):
|
||||||
|
ProjectContributor.objects.create(project=self.project, user=self.bob, added_by=self.alice)
|
||||||
|
self.project.sync_creator_tags()
|
||||||
|
self._add_manual_creator_tag('lizo')
|
||||||
|
self.gate()
|
||||||
|
self.client.login(username='Alice', password='pw')
|
||||||
|
resp = self.client.get(reverse('library:project_edit', args=['test-pack']))
|
||||||
|
# Manual tag visible; account-backed creator tags (alice, bob) hidden.
|
||||||
|
self.assertContains(resp, 'creator:lizo')
|
||||||
|
self.assertNotContains(resp, 'creator:alice')
|
||||||
|
self.assertNotContains(resp, 'creator:bob')
|
||||||
|
|
||||||
|
def test_edit_removing_manual_creator_tag_deletes_it(self):
|
||||||
|
self.project.sync_creator_tags()
|
||||||
|
self._add_manual_creator_tag('lizo')
|
||||||
|
self.gate()
|
||||||
|
self.client.login(username='Alice', password='pw')
|
||||||
|
resp = self.client.post(
|
||||||
|
reverse('library:project_edit', args=['test-pack']),
|
||||||
|
{'title': 'Test Pack', 'category': 'mod', 'description': 'x', 'tags': ''},
|
||||||
|
)
|
||||||
|
self.assertRedirects(resp, reverse('library:project_detail', args=['test-pack']))
|
||||||
|
# Manual creator tag removed from the form is now deleted...
|
||||||
|
self.assertFalse(
|
||||||
|
TagList.objects.filter(project=self.project, tag__name='lizo').exists()
|
||||||
|
)
|
||||||
|
# ...while the account-backed owner creator tag survives.
|
||||||
|
self.assertTrue(
|
||||||
|
TagList.objects.filter(project=self.project, tag__name='alice').exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_edit_keeps_manual_creator_tag_when_resubmitted(self):
|
||||||
|
self.project.sync_creator_tags()
|
||||||
|
self._add_manual_creator_tag('lizo')
|
||||||
|
self.gate()
|
||||||
|
self.client.login(username='Alice', password='pw')
|
||||||
|
resp = self.client.post(
|
||||||
|
reverse('library:project_edit', args=['test-pack']),
|
||||||
|
{'title': 'Test Pack', 'category': 'mod', 'description': 'x',
|
||||||
|
'tags': 'creator:lizo species:dragon'},
|
||||||
|
)
|
||||||
|
self.assertRedirects(resp, reverse('library:project_detail', args=['test-pack']))
|
||||||
|
self.assertTrue(
|
||||||
|
TagList.objects.filter(project=self.project, tag__name='lizo').exists()
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
TagList.objects.filter(project=self.project, tag__name='dragon').exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UGCBrowseTests(UGCGatedTestCase):
|
class UGCBrowseTests(UGCGatedTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -156,13 +156,30 @@ def _tags_from_text(text):
|
|||||||
return pairs
|
return pairs
|
||||||
|
|
||||||
|
|
||||||
|
def _managed_creator_names(project):
|
||||||
|
"""Slugified usernames of the owner + contributors — the creator tags that
|
||||||
|
sync_creator_tags manages automatically. Creator tags that are NOT backed
|
||||||
|
by an account (e.g. an offline artist) are treated as manual and stay
|
||||||
|
editable/removable."""
|
||||||
|
names = {slugify_tag(project.owner.username)}
|
||||||
|
names.update(
|
||||||
|
slugify_tag(c.user.username)
|
||||||
|
for c in project.contributors.select_related('user')
|
||||||
|
)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
def _apply_tags(project, raw_tags, actor):
|
def _apply_tags(project, raw_tags, actor):
|
||||||
"""Replace a project's manual tags (auto-creating new ones). Creator tags
|
"""Replace a project's manual tags (auto-creating new ones). Account-backed
|
||||||
are managed separately by sync_creator_tags."""
|
creator tags (owner + contributors) are managed by sync_creator_tags and
|
||||||
|
preserved; any other creator tag is editable like any other manual tag."""
|
||||||
creator_cat = TagCategory.objects.filter(slug='creator').first()
|
creator_cat = TagCategory.objects.filter(slug='creator').first()
|
||||||
to_delete = project.tag_links.all()
|
to_delete = project.tag_links.all()
|
||||||
if creator_cat is not None:
|
if creator_cat is not None:
|
||||||
to_delete = to_delete.exclude(tag__category=creator_cat)
|
to_delete = to_delete.exclude(
|
||||||
|
tag__category=creator_cat,
|
||||||
|
tag__name__in=_managed_creator_names(project),
|
||||||
|
)
|
||||||
to_delete.delete()
|
to_delete.delete()
|
||||||
|
|
||||||
for category_slug, name in _tags_from_text(raw_tags):
|
for category_slug, name in _tags_from_text(raw_tags):
|
||||||
@@ -178,11 +195,18 @@ def _apply_tags(project, raw_tags, actor):
|
|||||||
|
|
||||||
|
|
||||||
def _current_tags(project):
|
def _current_tags(project):
|
||||||
"""Serialize a project's non-creator tags back to 'category:name' form."""
|
"""Serialize a project's editable tags back to 'category:name' form.
|
||||||
|
|
||||||
|
Account-backed creator tags (owner + contributors) are auto-managed and
|
||||||
|
hidden; manual creator tags (no matching account) remain visible so they
|
||||||
|
can be removed."""
|
||||||
creator_cat = TagCategory.objects.filter(slug='creator').first()
|
creator_cat = TagCategory.objects.filter(slug='creator').first()
|
||||||
qs = project.tag_links.select_related('tag__category').all()
|
qs = project.tag_links.select_related('tag__category').all()
|
||||||
if creator_cat is not None:
|
if creator_cat is not None:
|
||||||
qs = qs.exclude(tag__category=creator_cat)
|
qs = qs.exclude(
|
||||||
|
tag__category=creator_cat,
|
||||||
|
tag__name__in=_managed_creator_names(project),
|
||||||
|
)
|
||||||
return ' '.join(f'{tl.tag.category.slug}:{tl.tag.name}' for tl in qs)
|
return ' '.join(f'{tl.tag.category.slug}:{tl.tag.name}' for tl in qs)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,11 @@
|
|||||||
<a href="{% url 'profiles:settings' %}">
|
<a href="{% url 'profiles:settings' %}">
|
||||||
<i class="fas fa-key"></i> API Tokens
|
<i class="fas fa-key"></i> API Tokens
|
||||||
</a>
|
</a>
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<a href="{% url 'admin:index' %}">
|
||||||
|
<i class="fas fa-shield-alt"></i> Admin panel
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
<form method="post" action="{% url 'profiles:logout' %}" style="display: inline;">
|
<form method="post" action="{% url 'profiles:logout' %}" style="display: inline;">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit" class="logout-button">
|
<button type="submit" class="logout-button">
|
||||||
|
|||||||
Reference in New Issue
Block a user