wbwiki 2.2.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wbwiki/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
wbwiki/admin.py ADDED
@@ -0,0 +1,18 @@
1
+ from django.contrib import admin
2
+ from wbwiki.models import WikiArticle, WikiArticleRelationship
3
+
4
+
5
+ class WikiArticleRelationshipInline(admin.TabularInline):
6
+ model = WikiArticleRelationship
7
+ extra = 0
8
+ raw_id_fields = ["content_type", "wiki"]
9
+
10
+
11
+ @admin.register(WikiArticleRelationship)
12
+ class WikiArticleRelationshipAdmin(admin.ModelAdmin):
13
+ pass
14
+
15
+
16
+ @admin.register(WikiArticle)
17
+ class WikiArticleModelAdmin(admin.ModelAdmin):
18
+ inlines = [WikiArticleRelationshipInline]
wbwiki/apps.py ADDED
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class WbwikiConfig(AppConfig):
5
+ name = "wbwiki"
@@ -0,0 +1,16 @@
1
+ from django.contrib.contenttypes.models import ContentType
2
+ from django.utils.translation import gettext as _
3
+ from dynamic_preferences.preferences import Section
4
+ from dynamic_preferences.registries import global_preferences_registry
5
+ from dynamic_preferences.types import ModelMultipleChoicePreference
6
+
7
+ mailing_section = Section("wbwiki")
8
+
9
+
10
+ @global_preferences_registry.register
11
+ class AllowedTypeWikiRelationshipPreference(ModelMultipleChoicePreference):
12
+ section = mailing_section
13
+ name = "allowed_type_wiki_relationship"
14
+ queryset = ContentType.objects.all()
15
+ default = []
16
+ verbose_name = _("Allowed Type Wiki Relationship")
wbwiki/factories.py ADDED
@@ -0,0 +1,30 @@
1
+ import factory
2
+ from django.contrib.contenttypes.models import ContentType
3
+ from wbwiki.models import WikiArticle, WikiArticleRelationship
4
+
5
+
6
+ class WikiArticleFactory(factory.django.DjangoModelFactory):
7
+ class Meta:
8
+ model = WikiArticle
9
+
10
+ title = factory.Faker("pystr")
11
+ summary = factory.Faker("pystr")
12
+ content = factory.Faker("pystr")
13
+
14
+
15
+ class AbstractPublicationFactory(factory.django.DjangoModelFactory):
16
+ object_id = factory.SelfAttribute("content_object.id")
17
+ content_type = factory.LazyAttribute(lambda o: ContentType.objects.get_for_model(o.content_object))
18
+
19
+ class Meta:
20
+ exclude = ["content_object"]
21
+ abstract = True
22
+
23
+
24
+ class WikiArticleRelationshipFactory(AbstractPublicationFactory):
25
+ class Meta:
26
+ model = WikiArticleRelationship
27
+
28
+ wiki = factory.SubFactory(WikiArticleFactory)
29
+ content_object = factory.SubFactory("wbcore.contrib.authentication.factories.AuthenticatedPersonFactory")
30
+ # content_object = factory.SubFactory(WikiArticleFactory)
@@ -0,0 +1,33 @@
1
+ # Generated by Django 4.1.8 on 2023-04-19 05:27
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ initial = True
8
+
9
+ dependencies = [
10
+ ("tags", "0001_initial"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name="WikiArticle",
16
+ fields=[
17
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
18
+ ("tag_detail_endpoint", models.CharField(blank=True, max_length=255, null=True)),
19
+ ("tag_representation", models.CharField(blank=True, max_length=512, null=True)),
20
+ ("title", models.CharField(max_length=1024)),
21
+ ("content", models.TextField(default="")),
22
+ ("summary", models.TextField(default="")),
23
+ (
24
+ "tags",
25
+ models.ManyToManyField(blank=True, related_name="%(app_label)s_%(class)s_items", to="tags.tag"),
26
+ ),
27
+ ],
28
+ options={
29
+ "verbose_name": "Wiki Article",
30
+ "verbose_name_plural": "Wiki Articles",
31
+ },
32
+ ),
33
+ ]
@@ -0,0 +1,52 @@
1
+ # Generated by Django 4.1.9 on 2023-07-11 10:27
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("contenttypes", "0002_remove_content_type_name"),
10
+ ("wbwiki", "0001_initial_squashed_0004_alter_wikiarticle_tags"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name="WikiArticleRelationship",
16
+ fields=[
17
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
18
+ ("computed_str", models.CharField(blank=True, max_length=512, null=True, verbose_name="Name")),
19
+ ("object_id", models.PositiveIntegerField(verbose_name="Related Item")),
20
+ (
21
+ "content_type",
22
+ models.ForeignKey(
23
+ on_delete=django.db.models.deletion.CASCADE,
24
+ to="contenttypes.contenttype",
25
+ verbose_name="Item Type",
26
+ ),
27
+ ),
28
+ (
29
+ "wiki",
30
+ models.ForeignKey(
31
+ on_delete=django.db.models.deletion.CASCADE,
32
+ related_name="relationships",
33
+ to="wbwiki.wikiarticle",
34
+ ),
35
+ ),
36
+ ],
37
+ options={
38
+ "verbose_name": "Wiki Relationship",
39
+ "verbose_name_plural": "Wiki Relationships",
40
+ },
41
+ ),
42
+ migrations.AddIndex(
43
+ model_name="wikiarticlerelationship",
44
+ index=models.Index(fields=["content_type", "object_id"], name="wbwiki_wiki_content_9ba127_idx"),
45
+ ),
46
+ migrations.AddConstraint(
47
+ model_name="wikiarticlerelationship",
48
+ constraint=models.UniqueConstraint(
49
+ fields=("wiki", "content_type", "object_id"), name="unique_wiki_article_relationship"
50
+ ),
51
+ ),
52
+ ]
@@ -0,0 +1,43 @@
1
+ # Generated by Django 4.2.8 on 2024-01-03 08:54
2
+
3
+ from contextlib import suppress
4
+
5
+ from django.apps import apps
6
+ from django.contrib.contenttypes.models import ContentType
7
+ from django.db import migrations
8
+
9
+
10
+ def migrate_content_type(apps, schema_editor):
11
+ WikiArticleRelationship = apps.get_model("wbwiki", "WikiArticleRelationship")
12
+
13
+ for model_name in [
14
+ "Classification",
15
+ "Instrument",
16
+ "ClassificationGroup",
17
+ "Deal",
18
+ "Exchange",
19
+ "InstrumentClassificationRelatedInstrument",
20
+ "InstrumentClassificationThroughModel",
21
+ "InstrumentFavoriteGroup",
22
+ "InstrumentList",
23
+ "InstrumentListThroughModel",
24
+ "InstrumentRequest",
25
+ "RelatedInstrumentThroughModel",
26
+ "InstrumentPrice",
27
+ ]:
28
+ with suppress(ContentType.DoesNotExist):
29
+ old_ct = ContentType.objects.get(app_label="wbportfolio", model=model_name.lower())
30
+ new_ct = ContentType.objects.get(app_label="wbfdm", model=model_name.lower())
31
+ WikiArticleRelationship.objects.filter(content_type_id=old_ct.id).update(content_type_id=new_ct.id)
32
+
33
+
34
+ class Migration(migrations.Migration):
35
+ dependencies = (
36
+ [
37
+ ("wbwiki", "0005_wikiarticlerelationship_and_more"),
38
+ ("wbfdm", "0012_instrumentprice_created_instrumentprice_modified"),
39
+ ]
40
+ if apps.is_installed("wbfdm")
41
+ else [("wbwiki", "0005_wikiarticlerelationship_and_more")]
42
+ )
43
+ operations = [migrations.RunPython(migrate_content_type)]
File without changes
wbwiki/models.py ADDED
@@ -0,0 +1,76 @@
1
+ import reversion
2
+ from django.contrib.contenttypes.fields import GenericForeignKey
3
+ from django.contrib.contenttypes.models import ContentType
4
+ from django.db import models
5
+ from django.utils.translation import gettext_lazy as _
6
+ from rest_framework.reverse import reverse
7
+ from wbcore.contrib.tags.models import TagModelMixin
8
+ from wbcore.models import WBModel
9
+ from wbcore.utils.models import ComplexToStringMixin
10
+
11
+
12
+ @reversion.register()
13
+ class WikiArticle(TagModelMixin, WBModel):
14
+ title = models.CharField(max_length=1024)
15
+ summary = models.TextField(default="")
16
+ content = models.TextField(default="")
17
+
18
+ def __str__(self) -> str:
19
+ return f"{self.title}"
20
+
21
+ @classmethod
22
+ def get_endpoint_basename(cls):
23
+ return "wbwiki:wikiarticle"
24
+
25
+ @classmethod
26
+ def get_representation_endpoint(cls):
27
+ return "wbwiki:wikiarticle-list"
28
+
29
+ @classmethod
30
+ def get_representation_value_key(cls):
31
+ return "id"
32
+
33
+ @classmethod
34
+ def get_representation_label_key(cls):
35
+ return "{{ title }}"
36
+
37
+ def get_tag_detail_endpoint(self):
38
+ return reverse("wbwiki:wikiarticle-detail", [self.id])
39
+
40
+ def get_tag_representation(self):
41
+ return self.title
42
+
43
+ class Meta:
44
+ verbose_name = "Wiki Article"
45
+ verbose_name_plural = "Wiki Articles"
46
+
47
+
48
+ class WikiArticleRelationship(ComplexToStringMixin, models.Model):
49
+ wiki = models.ForeignKey(to="wbwiki.WikiArticle", related_name="relationships", on_delete=models.CASCADE)
50
+ content_type = models.ForeignKey(ContentType, verbose_name=_("Item Type"), on_delete=models.CASCADE)
51
+ object_id = models.PositiveIntegerField(verbose_name=_("Related Item"))
52
+ content_object = GenericForeignKey("content_type", "object_id")
53
+
54
+ def __str__(self) -> str:
55
+ return f"{self.wiki} -> {self.content_object}"
56
+
57
+ def compute_str(self) -> str:
58
+ return f"{self.content_object}"
59
+
60
+ class Meta:
61
+ verbose_name = _("Wiki Relationship")
62
+ verbose_name_plural = _("Wiki Relationships")
63
+ constraints = [
64
+ models.UniqueConstraint(
65
+ name="unique_wiki_article_relationship", fields=["wiki", "content_type", "object_id"]
66
+ ),
67
+ ]
68
+ indexes = [models.Index(fields=["content_type", "object_id"])]
69
+
70
+ @classmethod
71
+ def get_representation_value_key(cls):
72
+ return "id"
73
+
74
+ @classmethod
75
+ def get_representation_label_key(cls):
76
+ return "{{wiki}} -> {{computed_str}}"
wbwiki/preferences.py ADDED
@@ -0,0 +1,10 @@
1
+ from django.contrib.contenttypes.models import ContentType
2
+ from django.db.utils import ProgrammingError
3
+ from dynamic_preferences.registries import global_preferences_registry
4
+
5
+
6
+ def get_allowed_type_wiki_relationship():
7
+ try:
8
+ return global_preferences_registry.manager()["wbwiki__allowed_type_wiki_relationship"]
9
+ except (RuntimeError, ProgrammingError):
10
+ return ContentType.objects.none()
wbwiki/serializers.py ADDED
@@ -0,0 +1,91 @@
1
+ from django.utils.translation import gettext as _
2
+ from rest_framework import serializers as rf_serializers
3
+ from rest_framework.reverse import reverse
4
+ from wbcore import serializers
5
+ from wbcore.content_type.serializers import (
6
+ ContentTypeRepresentationSerializer,
7
+ DynamicObjectIDRepresentationSerializer,
8
+ )
9
+ from wbcore.contrib.tags.serializers import TagSerializerMixin
10
+ from wbwiki.models import WikiArticle, WikiArticleRelationship
11
+
12
+ from .preferences import get_allowed_type_wiki_relationship
13
+
14
+
15
+ class WikiArticleRepresentationSerializer(serializers.RepresentationSerializer):
16
+ class Meta:
17
+ model = WikiArticle
18
+ fields = ("id", "title")
19
+
20
+
21
+ class WikiArticleModelSerializer(TagSerializerMixin, serializers.ModelSerializer):
22
+ @serializers.register_only_instance_resource()
23
+ def relationship_resources(self, instance, request, user, **kwargs):
24
+ resources = {"relationship": reverse("wiki:wiki-relationship-list", args=[instance.id], request=request)}
25
+ return resources
26
+
27
+ class Meta:
28
+ model = WikiArticle
29
+ fields = (
30
+ "id",
31
+ "title",
32
+ "summary",
33
+ "content",
34
+ "tags",
35
+ "_tags",
36
+ "_additional_resources",
37
+ )
38
+
39
+
40
+ class WikiArticleRelationshipModelSerializer(serializers.ModelSerializer):
41
+ _wiki = WikiArticleRepresentationSerializer(source="wiki")
42
+ _content_type = ContentTypeRepresentationSerializer(
43
+ source="content_type",
44
+ label_key="{{model_title}}",
45
+ allowed_types=get_allowed_type_wiki_relationship(),
46
+ )
47
+ _object_id = DynamicObjectIDRepresentationSerializer(
48
+ source="object_id",
49
+ optional_get_parameters={"content_type": "content_type"},
50
+ depends_on=[{"field": "content_type", "options": {}}],
51
+ )
52
+
53
+ @serializers.register_only_instance_resource()
54
+ def additional_resources(self, instance, request, user, view, **kwargs):
55
+ if instance and hasattr(instance.content_object, "get_endpoint_basename"):
56
+ return {
57
+ "object_endpoint": reverse(
58
+ f"{instance.content_object.get_endpoint_basename()}-detail",
59
+ args=[instance.object_id],
60
+ request=request,
61
+ )
62
+ }
63
+
64
+ class Meta:
65
+ model = WikiArticleRelationship
66
+ dependency_map = {"object_id": ["content_type"]}
67
+ fields = (
68
+ "id",
69
+ "content_type",
70
+ "_content_type",
71
+ "object_id",
72
+ "_object_id",
73
+ "wiki",
74
+ "_wiki",
75
+ "computed_str",
76
+ "_additional_resources",
77
+ )
78
+
79
+ def validate(self, validated_data):
80
+ content_type = validated_data.get("content_type", self.instance.content_type if self.instance else None)
81
+ wiki = validated_data.get("wiki", self.instance.wiki if self.instance else None)
82
+ object_id = validated_data.get("object_id", self.instance.object_id if self.instance else None)
83
+
84
+ if content_type and wiki and object_id:
85
+ qs = WikiArticleRelationship.objects.filter(wiki=wiki, content_type=content_type, object_id=object_id)
86
+ qs = qs.exclude(id=self.instance.id) if self.instance else qs
87
+ if qs.exists():
88
+ raise rf_serializers.ValidationError(
89
+ {"object_id": _("Relationship with wiki: {} already exists").format(wiki)}
90
+ )
91
+ return super().validate(validated_data)
File without changes
@@ -0,0 +1,13 @@
1
+ from django.apps import apps
2
+ from django.db import connection
3
+ from django.db.models.signals import pre_migrate
4
+ from pytest_factoryboy import register
5
+ from wbcore.contrib.geography.tests.signals import app_pre_migration
6
+ from wbwiki.factories import WikiArticleFactory, WikiArticleRelationshipFactory
7
+
8
+ register(WikiArticleFactory)
9
+ register(WikiArticleRelationshipFactory)
10
+
11
+ from .signals import *
12
+
13
+ pre_migrate.connect(app_pre_migration, sender=apps.get_app_config("wbwiki"))
@@ -0,0 +1,13 @@
1
+ from django.contrib.contenttypes.models import ContentType
2
+ from django.dispatch import receiver
3
+ from wbcore.test.signals import custom_update_kwargs
4
+ from wbwiki.factories import WikiArticleRelationshipFactory
5
+ from wbwiki.viewsets import ContentObjectWikiArticleModelViewSet
6
+
7
+
8
+ @receiver(custom_update_kwargs, sender=ContentObjectWikiArticleModelViewSet)
9
+ def receive_kwargs_content_object(sender, *args, **kwargs):
10
+ if wiki := kwargs.get("obj_factory"):
11
+ WikiArticleRelationshipFactory(wiki=wiki, content_object=wiki)
12
+ return {"content_type": ContentType.objects.get_for_model(wiki).id, "content_id": wiki.id}
13
+ return {}
@@ -0,0 +1,2 @@
1
+ def test_initial():
2
+ assert True
wbwiki/tests/tests.py ADDED
@@ -0,0 +1,17 @@
1
+ import pytest
2
+ from wbcore.test import GenerateTest, default_config
3
+
4
+ config = {}
5
+ for key, value in default_config.items():
6
+ config[key] = list(
7
+ filter(
8
+ lambda x: x.__module__.startswith("wbwiki") and x.__name__ not in ["WikiArticleRelationshipModelViewSet"],
9
+ value,
10
+ )
11
+ )
12
+
13
+
14
+ @pytest.mark.django_db
15
+ @GenerateTest(config)
16
+ class TestProject:
17
+ pass
wbwiki/urls.py ADDED
@@ -0,0 +1,26 @@
1
+ from django.urls import include, path
2
+ from wbcore.routers import WBCoreRouter
3
+ from wbwiki import viewsets
4
+
5
+ router = WBCoreRouter()
6
+ router.register(r"wikiarticle", viewsets.WikiArticleModelViewSet, basename="wikiarticle")
7
+
8
+ wiki_router = WBCoreRouter()
9
+ wiki_router.register(
10
+ r"relationship",
11
+ viewsets.WikiArticleRelationshipModelViewSet,
12
+ basename="wiki-relationship",
13
+ )
14
+
15
+ content_object_wiki_router = WBCoreRouter()
16
+ content_object_wiki_router.register(
17
+ r"contentobjectwiki",
18
+ viewsets.ContentObjectWikiArticleModelViewSet,
19
+ basename="contentobjectwiki",
20
+ )
21
+
22
+ urlpatterns = [
23
+ path("", include(router.urls)),
24
+ path("wiki/<wiki_id>/", include(wiki_router.urls)),
25
+ path("contentobjectwiki/<int:content_type>/<int:content_id>/", include(content_object_wiki_router.urls)),
26
+ ]
@@ -0,0 +1,5 @@
1
+ from .wikis import (
2
+ ContentObjectWikiArticleModelViewSet,
3
+ WikiArticleModelViewSet,
4
+ WikiArticleRelationshipModelViewSet,
5
+ )
@@ -0,0 +1,4 @@
1
+ from .wikis import (
2
+ ContentObjectWikiArticleButtonConfig,
3
+ WikiArticleRelationshipButtonConfig,
4
+ )
@@ -0,0 +1,51 @@
1
+ from django.utils.translation import gettext as _
2
+ from rest_framework.reverse import reverse
3
+ from wbcore import serializers as wb_serializers
4
+ from wbcore.contrib.icons import WBIcon
5
+ from wbcore.enums import RequestType
6
+ from wbcore.metadata.configs import buttons as bt
7
+ from wbcore.metadata.configs.buttons.view_config import ButtonViewConfig
8
+ from wbcore.metadata.configs.display.instance_display.shortcuts import (
9
+ create_simple_display,
10
+ )
11
+ from wbwiki.models import WikiArticle
12
+ from wbwiki.serializers import WikiArticleRepresentationSerializer
13
+
14
+
15
+ class WikiArticleRelationshipButtonConfig(ButtonViewConfig):
16
+ def get_custom_instance_buttons(self):
17
+ return self.get_custom_list_instance_buttons()
18
+
19
+ def get_custom_list_instance_buttons(self):
20
+ return {
21
+ bt.WidgetButton(key="object_endpoint", label="{{computed_str}}", icon=WBIcon.CLIPBOARD.icon),
22
+ }
23
+
24
+
25
+ class ContentObjectWikiArticleButtonConfig(ButtonViewConfig):
26
+ def get_custom_buttons(self):
27
+ if not self.view.kwargs.get("pk", None):
28
+
29
+ class WikiArticleSerializer(wb_serializers.Serializer):
30
+ wiki = wb_serializers.PrimaryKeyRelatedField(
31
+ queryset=WikiArticle.objects.all(),
32
+ required=True,
33
+ label=_("Wiki"),
34
+ )
35
+ _wiki = WikiArticleRepresentationSerializer(source="wiki")
36
+
37
+ return {
38
+ bt.ActionButton(
39
+ identifiers=("wbwiki:wikiarticle",),
40
+ method=RequestType.PATCH,
41
+ endpoint=f"{reverse('wbwiki:wikiarticle-linkwiki', args=[], request=self.request)}?content_type={self.view.kwargs['content_type']}&content_id={self.view.kwargs['content_id']}",
42
+ action_label=_("Add Existing Wiki"),
43
+ title=_("Add Existing Wiki"),
44
+ label=_("Add Existing Wiki"),
45
+ icon=WBIcon.LINK.icon,
46
+ serializer=WikiArticleSerializer,
47
+ description_fields="<p>Link item to Existing Wiki</p><p>Are you sure you want to proceed?</p>",
48
+ instance_display=create_simple_display([["wiki"]]),
49
+ )
50
+ }
51
+ return {}
@@ -0,0 +1 @@
1
+ from .wikis import WikiArticleDisplayConfig, WikiArticleRelationshipDisplayConfig
@@ -0,0 +1,75 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.metadata.configs import display as dp
3
+ from wbcore.metadata.configs.display.instance_display import (
4
+ Display,
5
+ Inline,
6
+ Layout,
7
+ Page,
8
+ Style,
9
+ create_simple_display,
10
+ )
11
+ from wbcore.metadata.configs.display.instance_display.operators import default
12
+ from wbcore.metadata.configs.display.view_config import DisplayViewConfig
13
+
14
+
15
+ class WikiArticleRelationshipDisplayConfig(DisplayViewConfig):
16
+ def get_list_display(self) -> dp.ListDisplay:
17
+ return dp.ListDisplay(
18
+ fields=[
19
+ dp.Field(key="content_type", label="Item Type"),
20
+ dp.Field(key="computed_str", label="Related Item"),
21
+ ]
22
+ )
23
+
24
+ def get_instance_display(self) -> Display:
25
+ return create_simple_display([["content_type", "object_id"]])
26
+
27
+
28
+ class WikiArticleDisplayConfig(DisplayViewConfig):
29
+ def get_list_display(self) -> dp.ListDisplay:
30
+ return dp.ListDisplay(
31
+ fields=[
32
+ dp.Field(key="title", label="Title"),
33
+ dp.Field(key="summary", label="Summary"),
34
+ dp.Field(key="tags", label="Tags"),
35
+ ]
36
+ )
37
+
38
+ def _get_custom_instance_display(self) -> Display:
39
+ return Display(
40
+ pages=[
41
+ Page(
42
+ title=_("Main Information"),
43
+ layouts={
44
+ default(): Layout(
45
+ grid_template_areas=[["title"], ["summary"], ["tags"], ["content"]],
46
+ grid_template_columns=[
47
+ "minmax(min-content, 1fr)",
48
+ ],
49
+ ),
50
+ },
51
+ ),
52
+ Page(
53
+ title=_("Relationship"),
54
+ layouts={
55
+ default(): Layout(
56
+ grid_template_areas=[["relationship_key"]],
57
+ inlines=[Inline(key="relationship_key", endpoint="relationship")],
58
+ grid_template_columns=[
59
+ "minmax(min-content, 1fr)",
60
+ ],
61
+ grid_auto_rows=Style.MIN_CONTENT,
62
+ ),
63
+ },
64
+ ),
65
+ ]
66
+ )
67
+
68
+ def get_instance_display(self) -> Display:
69
+ display = (
70
+ self._get_custom_instance_display()
71
+ if "pk" in self.view.kwargs
72
+ else create_simple_display([["title", "summary", "tags", "content"]])
73
+ )
74
+
75
+ return display
@@ -0,0 +1,4 @@
1
+ from .wikis import (
2
+ ContentObjectWikiArticleEndpointConfig,
3
+ WikiArticleRelationshipEndpointConfig,
4
+ )
@@ -0,0 +1,20 @@
1
+ from rest_framework.reverse import reverse
2
+ from wbcore.metadata.configs.endpoints import EndpointViewConfig
3
+
4
+
5
+ class WikiArticleRelationshipEndpointConfig(EndpointViewConfig):
6
+ def get_endpoint(self, **kwargs):
7
+ return reverse(
8
+ "wiki:wiki-relationship-list",
9
+ args=[self.view.kwargs["wiki_id"]],
10
+ request=self.request,
11
+ )
12
+
13
+
14
+ class ContentObjectWikiArticleEndpointConfig(EndpointViewConfig):
15
+ def get_endpoint(self, **kwargs):
16
+ return reverse(
17
+ "wiki:contentobjectwiki-list",
18
+ args=[self.view.kwargs["content_type"], self.view.kwargs["content_id"]],
19
+ request=self.request,
20
+ )
@@ -0,0 +1 @@
1
+ from .wikis import WIKI_MENU, WIKI_MENU_ITEM
@@ -0,0 +1,21 @@
1
+ from wbcore.menus import ItemPermission, Menu, MenuItem
2
+
3
+ WIKI_MENU_ITEM = MenuItem(
4
+ label="WIKI",
5
+ endpoint="wbwiki:wikiarticle-list",
6
+ add=MenuItem(
7
+ label="Create a wiki article",
8
+ endpoint="wbwiki:wikiarticle-list",
9
+ permission=ItemPermission(
10
+ permissions=["wbwiki.create_wikiarticle"],
11
+ ),
12
+ ),
13
+ permission=ItemPermission(
14
+ permissions=["wbwiki.view_wikiarticle"],
15
+ ),
16
+ )
17
+
18
+ WIKI_MENU = Menu(
19
+ label="WIKI",
20
+ items=[WIKI_MENU_ITEM],
21
+ )
File without changes
@@ -0,0 +1,107 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+ from rest_framework import status
3
+ from rest_framework.decorators import action
4
+ from rest_framework.response import Response
5
+ from reversion.views import RevisionMixin
6
+ from wbcore import viewsets
7
+ from wbcore.contrib.authentication.authentication import JWTCookieAuthentication
8
+ from wbwiki.models import WikiArticle, WikiArticleRelationship
9
+ from wbwiki.serializers import (
10
+ WikiArticleModelSerializer,
11
+ WikiArticleRelationshipModelSerializer,
12
+ )
13
+
14
+ from .buttons import (
15
+ ContentObjectWikiArticleButtonConfig,
16
+ WikiArticleRelationshipButtonConfig,
17
+ )
18
+ from .display import WikiArticleDisplayConfig, WikiArticleRelationshipDisplayConfig
19
+ from .endpoints import (
20
+ ContentObjectWikiArticleEndpointConfig,
21
+ WikiArticleRelationshipEndpointConfig,
22
+ )
23
+
24
+
25
+ class WikiArticleModelViewSet(RevisionMixin, viewsets.ModelViewSet):
26
+ queryset = WikiArticle.objects.all()
27
+ serializer_class = WikiArticleModelSerializer
28
+ # search_fields = ("title", "summary", "content", "tags__title")
29
+ filterset_fields = {
30
+ "title": ["icontains"],
31
+ "summary": ["icontains"],
32
+ "tags": ["exact"],
33
+ }
34
+
35
+ display_config_class = WikiArticleDisplayConfig
36
+
37
+ @action(detail=False, methods=["PATCH"], authentication_classes=[JWTCookieAuthentication])
38
+ def linkwiki(self, request, pk=None):
39
+ content_type_id = request.GET.get("content_type")
40
+ object_id = request.GET.get("content_id")
41
+ wiki_id = request.POST.get("wiki")
42
+
43
+ if content_type_id and object_id:
44
+ if wiki_id:
45
+ wiki_relationship, created = WikiArticleRelationship.objects.get_or_create(
46
+ wiki_id=wiki_id,
47
+ content_type_id=content_type_id,
48
+ object_id=object_id,
49
+ )
50
+ if created:
51
+ message = _("Relationship Item has been added to wiki")
52
+ _status = status.HTTP_200_OK
53
+ else:
54
+ message = _("Wiki has already been linked to this Item")
55
+ _status = status.HTTP_400_BAD_REQUEST
56
+ else:
57
+ message = _("Wiki is mandatory")
58
+ _status = status.HTTP_400_BAD_REQUEST
59
+ else:
60
+ message = _("Relationship Item could not be linked to wiki")
61
+ _status = status.HTTP_400_BAD_REQUEST
62
+
63
+ return Response(
64
+ {"__notification": {"title": message}},
65
+ status=_status,
66
+ )
67
+
68
+
69
+ class ContentObjectWikiArticleModelViewSet(WikiArticleModelViewSet):
70
+ endpoint_config_class = ContentObjectWikiArticleEndpointConfig
71
+ button_config_class = ContentObjectWikiArticleButtonConfig
72
+
73
+ def get_queryset(self):
74
+ if (content_type_id := self.kwargs.get("content_type")) and (object_id := self.kwargs.get("content_id")):
75
+ return (
76
+ super()
77
+ .get_queryset()
78
+ .filter(relationships__content_type=content_type_id, relationships__object_id=object_id)
79
+ )
80
+ return WikiArticle.objects.none()
81
+
82
+ def create(self, request, *args, **kwargs):
83
+ response = super().create(request, *args, **kwargs)
84
+
85
+ if (content_type_id := self.kwargs.get("content_type")) and (object_id := self.kwargs.get("content_id")):
86
+ WikiArticleRelationship.objects.get_or_create(
87
+ wiki_id=response.data["instance"]["id"],
88
+ content_type_id=content_type_id,
89
+ object_id=object_id,
90
+ )
91
+
92
+ return response
93
+
94
+
95
+ class WikiArticleRelationshipModelViewSet(viewsets.ModelViewSet):
96
+ serializer_class = WikiArticleRelationshipModelSerializer
97
+ display_config_class = WikiArticleRelationshipDisplayConfig
98
+ endpoint_config_class = WikiArticleRelationshipEndpointConfig
99
+ button_config_class = WikiArticleRelationshipButtonConfig
100
+ queryset = WikiArticleRelationship.objects.all()
101
+ search_fields = ("computed_str", "content_type__model")
102
+ filterset_fields = {
103
+ "computed_str": ["icontains", "exact"],
104
+ }
105
+
106
+ def get_queryset(self):
107
+ return super().get_queryset().filter(wiki__id=self.kwargs["wiki_id"])
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.3
2
+ Name: wbwiki
3
+ Version: 2.2.1
4
+ Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
+ Requires-Dist: wbcore
@@ -0,0 +1,32 @@
1
+ wbwiki/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
2
+ wbwiki/admin.py,sha256=X0xF3PFKTHxk-Q58d9B7p1k9ectBDIkDFeCkm7a_frs,481
3
+ wbwiki/apps.py,sha256=1lFcha6_cuD4H4fII5HjurYNw4ZFX3YniNSIVh4C_yQ,87
4
+ wbwiki/dynamic_preferences_registry.py,sha256=1HrmDUTX3xpylnRQYFuDyhLIAiJymTVt7badJv-jSUQ,640
5
+ wbwiki/factories.py,sha256=qt0dONypTDvo1a79sf1Z75iRPwyqnw71R4yvMlvP-7c,1013
6
+ wbwiki/models.py,sha256=oSsKDdipdzdT9S_G06zeRaK0WvPcSefhWr3i5VXmpkA,2453
7
+ wbwiki/preferences.py,sha256=ZMu8uDBmojNTh_En0zo-shadVQJuJsvoRteM-1ys3oI,410
8
+ wbwiki/serializers.py,sha256=4BtLLVJFUE9ifscS9m_HuH7xDqp9MEwOL7kSjSnf_S0,3476
9
+ wbwiki/urls.py,sha256=ZSuKduXNEU0QP3MpsRtGOAud__xyDP80PMGJ_kJraOE,796
10
+ wbwiki/migrations/0001_initial_squashed_0004_alter_wikiarticle_tags.py,sha256=VIJ6j2RDcDz7DozJMeyU_B3bFk37_fmYNIxgFZFxQ8c,1162
11
+ wbwiki/migrations/0005_wikiarticlerelationship_and_more.py,sha256=DgYfOcLTPtEt1JAnkciFSg2fjMuh3oyIBmg8p-XCF_c,2006
12
+ wbwiki/migrations/0006_auto_20240103_0954.py,sha256=H5uuWBvv8_wddJzVaLpsxRiLZszZvNDliTGn-wVD3aI,1525
13
+ wbwiki/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ wbwiki/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ wbwiki/tests/conftest.py,sha256=5Q8p9xwqIbqVKk-4yI4_LkjQuYxqa2prbptCS5Veifg,472
16
+ wbwiki/tests/signals.py,sha256=vr8K_PNibs7nNLJHvkOA8PAHxSfSlfKUvZaRPyofxHw,639
17
+ wbwiki/tests/test_initial.py,sha256=iIKc7qc-FyYlXBNJpr2OgQ_xS5lkCWi1JIkypKEmHE4,36
18
+ wbwiki/tests/tests.py,sha256=zJZld_TEHJ-2jkGd0jKuCFrk00W-OPbGdXVLBE8WxtM,391
19
+ wbwiki/viewsets/__init__.py,sha256=BdAliWuZEZsomY1qKAcCAdqm5KURhgRzaegCAh2fVQU,135
20
+ wbwiki/viewsets/wikis.py,sha256=0gTeCrca2Jwt7AoBEQBEa83pWddztDbAg_6yieFcFoA,4168
21
+ wbwiki/viewsets/buttons/__init__.py,sha256=iq_FIYT7Gfu57DWJwmlv5UCO9CN9fQmSoYIgMy3v_aM,106
22
+ wbwiki/viewsets/buttons/wikis.py,sha256=oVrT80HhQGWH-MAoWKYiVaBIU-6Kog03mbxh8g9XjRY,2238
23
+ wbwiki/viewsets/display/__init__.py,sha256=wdRPBBlCxXFrvAEYN6ZXWU7HTvrTkbWhZxXFAI_e2JM,82
24
+ wbwiki/viewsets/display/wikis.py,sha256=fcsza-GjNPB-jXgLSZkd_MV1lGL_MfY810c5nbBZI9M,2618
25
+ wbwiki/viewsets/endpoints/__init__.py,sha256=kAg00bAPi5R2QZniB3xJcfkfzvL-_irqt5XVl-aLlog,110
26
+ wbwiki/viewsets/endpoints/wikis.py,sha256=8gpzQXvb_08Q5YssFNvYsj-J--4kQjCEtoCHRgbQU8Y,674
27
+ wbwiki/viewsets/menu/__init__.py,sha256=eribi4P7Tgj4VIJ_QM5Aiu2nwrDIw4DhnrdYsEYflZU,45
28
+ wbwiki/viewsets/menu/wikis.py,sha256=iiKag8cKusfvsCCT0k_-AEwGsWw_GWhAMlNQnuhJ65k,507
29
+ wbwiki/viewsets/preview/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ wbwiki-2.2.1.dist-info/METADATA,sha256=s5btveGzl4W62Ykq2qVH0YacTTwf1vxJkenPunoB6kQ,136
31
+ wbwiki-2.2.1.dist-info/WHEEL,sha256=aO3RJuuiFXItVSnAUEmQ0yRBvv9e1sbJh68PtuQkyAE,105
32
+ wbwiki-2.2.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.26.3
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any