Skip to content

Commit

Permalink
Delete FAQ model
Browse files Browse the repository at this point in the history
  • Loading branch information
samonaisi committed Feb 7, 2025
1 parent b5201aa commit 2c9f720
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 566 deletions.
2 changes: 1 addition & 1 deletion apps/commons/tests/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class PageInfoLimitOffsetPaginationTestCase(JwtAPITestCase):
@classmethod
def setUpTestData(cls):
super().setUpTestData()
Organization.objects.bulk_create(OrganizationFactory.build_batch(5, faq=None))
Organization.objects.bulk_create(OrganizationFactory.build_batch(5))

def test_first_page(self):
pagination = PageInfoLimitOffsetPagination()
Expand Down
49 changes: 0 additions & 49 deletions apps/commons/tests/test_process_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from apps.commons.test import JwtAPITestCase
from apps.feedbacks.factories import CommentFactory
from apps.organizations.factories import (
FaqFactory,
OrganizationFactory,
ProjectCategoryFactory,
TemplateFactory,
Expand Down Expand Up @@ -180,54 +179,6 @@ def test_update_comment_content(self):
content["content"],
)

def test_create_faq_content(self):
text = self.create_base64_image_text() + self.create_unlinked_image_text(
"Faq-images-detail", self.organization.code
)
self.client.force_authenticate(self.user)
payload = {
"title": faker.sentence(),
"content": text,
"organization_code": self.organization.code,
}
response = self.client.post(
reverse("Faq-list", args=(self.organization.code,)),
data=payload,
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
content = response.json()
self.assertEqual(len(content["images"]), 2)
for image in content["images"]:
image_id = image["id"]
self.assertIn(
reverse("Faq-images-detail", args=(self.organization.code, image_id)),
content["content"],
)

def test_update_faq_content(self):
organization = OrganizationFactory()
text = self.create_base64_image_text() + self.create_unlinked_image_text(
"Faq-images-detail", organization.code
)
self.client.force_authenticate(self.user)
FaqFactory(organization=organization)
payload = {
"content": text,
}
response = self.client.patch(
reverse("Faq-list", args=(organization.code,)),
data=payload,
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
content = response.json()
self.assertEqual(len(content["images"]), 2)
for image in content["images"]:
image_id = image["id"]
self.assertIn(
reverse("Faq-images-detail", args=(organization.code, image_id)),
content["content"],
)

def test_create_template_contents(self):
text1 = self.create_base64_image_text()
text2 = self.create_base64_image_text()
Expand Down
1 change: 0 additions & 1 deletion apps/files/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class ImageUploadToChoices(models.TextChoices):
ORGANIZATION_LOGO = "organization/logo/"
ORGANIZATION_BANNER = "organization/banner/"
ORGANIZATION_IMAGES = "organization/images/"
FAQ_IMAGES = "faq/images/"
CATEGORY_BACKGROUND = "category/background/"
TEMPLATE_IMAGES = "template/images/"
EMAIL_IMAGES = "email/images/"
Expand Down
5 changes: 1 addition & 4 deletions apps/files/management/commands/link_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from apps.commons.utils import process_unlinked_images
from apps.feedbacks.models import Comment
from apps.organizations.models import Faq, Template
from apps.organizations.models import Template
from apps.projects.models import BlogEntry, Project


Expand All @@ -24,9 +24,6 @@ def handle(self, *args, **options):
)
images2 = process_unlinked_images(instance, instance.blogentry_placeholder)
instance.images.add(*(images1 + images2))
for instance in Faq.objects.all():
images = process_unlinked_images(instance, instance.content)
instance.images.add(*images)
for instance in Comment.objects.all():
updated_at = instance.updated_at
images = process_unlinked_images(instance, instance.content)
Expand Down
2 changes: 0 additions & 2 deletions apps/files/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,6 @@ def get_related_organizations(self) -> List["Organization"]:
return [self.organization_banner.get()]
if self.organizations.exists():
return [self.organizations.get()]
if self.faqs.exists():
return [self.faqs.get().organization]
if self.project_category.exists():
return [self.project_category.get().organization]
if self.project_header.exists():
Expand Down
1 change: 0 additions & 1 deletion apps/organizations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class OrganizationAdmin(admin.ModelAdmin):
readonly_fields = (
"groups",
"images",
"faq",
)
search_fields = (
"code",
Expand Down
20 changes: 1 addition & 19 deletions apps/organizations/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from apps.accounts.factories import UserFactory
from apps.commons.factories import language_factory
from apps.commons.utils import get_test_image
from apps.organizations.models import Faq, Organization, ProjectCategory, Template
from apps.organizations.models import Organization, ProjectCategory, Template

faker = Faker()

Expand Down Expand Up @@ -44,24 +44,6 @@ def with_admin(self, create, extracted, **kwargs):
UserFactory(groups=[self.get_admins()])


class FaqFactory(factory.django.DjangoModelFactory):
class Meta:
model = Faq

title = factory.Faker("text", max_nb_chars=50)
content = factory.Faker("text")
organization = factory.LazyFunction(
lambda: OrganizationFactory()
) # Subfactory seems to not trigger `create()`

@classmethod
def create(cls, **kwargs):
instance = super().create(**kwargs)
instance.organization.faq = instance
instance.organization.save()
return instance


class TemplateFactory(factory.django.DjangoModelFactory):
class Meta:
model = Template
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Generated by Django 4.2.18 on 2025-02-07 14:31

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("organizations", "0018_remove_organization_wikipedia_tags_and_more"),
]

operations = [
migrations.AlterModelOptions(
name="organization",
options={
"permissions": (
("access_admin", "Can access the admin panel"),
("view_stat", "Can view stats"),
("view_org_project", "Can view community projects"),
("view_org_projectuser", "Can view community users"),
("view_org_peoplegroup", "Can view community groups"),
("lock_project", "Can lock and unlock a project"),
("duplicate_project", "Can duplicate a project"),
("change_locked_project", "Can update a locked project"),
("manage_accessrequest", "Can manage access requests"),
("view_project", "Can view projects"),
("add_project", "Can add projects"),
("change_project", "Can change projects"),
("delete_project", "Can delete projects"),
("view_projectmessage", "Can view project messages"),
("add_projectmessage", "Can add project messages"),
("change_projectmessage", "Can change project messages"),
("delete_projectmessage", "Can delete project messages"),
("view_projectuser", "Can view users"),
("add_projectuser", "Can add users"),
("change_projectuser", "Can change users"),
("delete_projectuser", "Can delete users"),
("view_peoplegroup", "Can view groups"),
("add_peoplegroup", "Can add groups"),
("change_peoplegroup", "Can change groups"),
("delete_peoplegroup", "Can delete groups"),
("view_news", "Can view news"),
("add_news", "Can add news"),
("change_news", "Can change news"),
("delete_news", "Can delete news"),
("view_event", "Can view event"),
("add_event", "Can add event"),
("change_event", "Can change event"),
("delete_event", "Can delete event"),
("view_instruction", "Can view instructions"),
("add_instruction", "Can add instructions"),
("change_instruction", "Can change instructions"),
("delete_instruction", "Can delete instructions"),
("add_tag", "Can add tags"),
("change_tag", "Can change tags"),
("delete_tag", "Can delete tags"),
("add_tagclassification", "Can add tag classifications"),
("change_tagclassification", "Can change tag classifications"),
("delete_tagclassification", "Can delete tag classifications"),
("add_projectcategory", "Can add project categories"),
("change_projectcategory", "Can change project categories"),
("delete_projectcategory", "Can delete project categories"),
("add_review", "Can add reviews"),
("change_review", "Can change reviews"),
("delete_review", "Can delete reviews"),
("add_comment", "Can add comments"),
("change_comment", "Can change comments"),
("delete_comment", "Can delete comments"),
("add_follow", "Can add follows"),
("change_follow", "Can change follows"),
("delete_follow", "Can delete follows"),
("add_invitation", "Can add invitation links"),
("change_invitation", "Can change invitation links"),
("delete_invitation", "Can delete invitation links"),
)
},
),
migrations.RemoveField(
model_name="organization",
name="faq",
),
migrations.DeleteModel(
name="Faq",
),
]
27 changes: 0 additions & 27 deletions apps/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,6 @@
from apps.accounts.models import ProjectUser


class Faq(models.Model, OrganizationRelated):
"""Frequently asked question of an organization.
title: CharField
Name of the FAQ.
content: TextField
Content of the FAQ.
images: ManyToManyField
Images used by the FAQ.
"""

title = models.CharField(max_length=255)
images = models.ManyToManyField("files.Image", related_name="faqs")
content = models.TextField(blank=True)

def get_related_organizations(self) -> List["Organization"]:
"""Return the organization related to this model."""
return [self.organization]


class Organization(PermissionsSetupModel, OrganizationRelated):
"""An Organization is a set of ProjectCategories contained in an OrganizationDirectory.
Expand Down Expand Up @@ -70,8 +50,6 @@ class Organization(PermissionsSetupModel, OrganizationRelated):
Main language of the organization.
website_url: CharField
Organization's website.
faq: OneToOneField, optional
The organization's frequently asked questions.
is_logo_visible_on_parent_dashboard: BooleanField
Whether to show or hide the organization's logo on the main
organization's portal.
Expand Down Expand Up @@ -145,9 +123,6 @@ class DefaultGroup(models.TextChoices):
"files.Image", related_name="organizations", blank=True
)

faq = models.OneToOneField(
Faq, on_delete=models.SET_NULL, null=True, related_name="organization"
)
identity_providers = models.ManyToManyField(
"keycloak.IdentityProvider", related_name="organizations", blank=True
)
Expand Down Expand Up @@ -207,7 +182,6 @@ class Meta:
write_only_subscopes = (
("tag", "tags"),
("tagclassification", "tag classifications"),
("faq", "faqs"),
("projectcategory", "project categories"),
("review", "reviews"),
("comment", "comments"),
Expand Down Expand Up @@ -264,7 +238,6 @@ def get_default_facilitators_permissions(self) -> QuerySet[Permission]:
for subscope in [
"tag",
"review",
"faq",
"projectcategory",
"tagclassification",
]
Expand Down
59 changes: 1 addition & 58 deletions apps/organizations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,66 +33,11 @@
ParentCategoryOrganizationError,
RootCategoryParentError,
)
from .models import Faq, Organization, ProjectCategory, Template
from .models import Organization, ProjectCategory, Template

logger = logging.getLogger(__name__)


class FaqSerializer(OrganizationRelatedSerializer):
images = ImageSerializer(many=True, read_only=True)
organization_code = serializers.SlugRelatedField(
write_only=True,
slug_field="code",
source="organization",
queryset=Organization.objects.all(),
)
images_ids = serializers.PrimaryKeyRelatedField(
many=True,
write_only=True,
queryset=Image.objects.all(),
source="images",
required=False,
)

class Meta:
model = Faq
fields = [
"id",
"title",
"content",
# read only
"images",
# write only
"organization_code",
"images_ids",
]

def get_related_organizations(self) -> List[Organization]:
"""Retrieve the related organizations"""
if "organization" in self.validated_data:
return [self.validated_data["organization"]]
return []

@transaction.atomic
def save(self, **kwargs):
if "content" in self.validated_data:
if not self.instance:
super(FaqSerializer, self).save(**kwargs)
text, images = process_text(
request=self.context["request"],
instance=self.instance,
text=self.validated_data["content"],
upload_to="faq/images/",
view="Faq-images-detail",
organization_code=self.instance.organization.code,
)
self.validated_data["content"] = text
self.validated_data["images"] = images + [
image for image in self.instance.images.all()
]
return super(FaqSerializer, self).save(**kwargs)


class OrganizationAddTeamMembersSerializer(serializers.Serializer):
organization = HiddenPrimaryKeyRelatedField(
required=False, write_only=True, queryset=Organization.objects.all()
Expand Down Expand Up @@ -201,7 +146,6 @@ class OrganizationSerializer(OrganizationRelatedSerializer):
# read_only
banner_image = ImageSerializer(read_only=True)
logo_image = ImageSerializer(read_only=True)
faq = FaqSerializer(many=False, read_only=True)
identity_providers = IdentityProviderSerializer(many=True, read_only=True)
google_sync_enabled = serializers.SerializerMethodField()
children = SlugRelatedField(
Expand Down Expand Up @@ -252,7 +196,6 @@ class Meta:
# read_only
"banner_image",
"logo_image",
"faq",
"children",
"google_sync_enabled",
"identity_providers",
Expand Down
Loading

0 comments on commit 2c9f720

Please sign in to comment.