Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/flatpages/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ class Meta:
class Moderation(ModeratedModel.Moderation):
excluded_fields = ModeratedModel.Moderation.excluded_fields + ['sites']

@classmethod
def get_serializer(self):
"""Return the serializer for the entity."""
from apps.flatpages.api.serializers import FlatPageSerializer

return FlatPageSerializer

def __str__(self) -> str:
return f'{self.path} -- {self.title}'

Expand Down
27 changes: 27 additions & 0 deletions apps/moderation/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from rest_framework import serializers

from apps.moderation.models import Change, ContentContribution


class ChangeSerializer(serializers.ModelSerializer):

content_object = serializers.SerializerMethodField()

class Meta:
model = Change
fields = ('content_object',)

def get_content_object(self, obj: Change):
return obj.content_object.serialize()


class ContentContributionSerializer(serializers.ModelSerializer):
"""Serializer for ContentContribution."""

absolute_url = serializers.CharField(required=False, read_only=True)
change = ChangeSerializer(read_only=True)

class Meta:
model = ContentContribution
# fields = '__all__'
fields = ('id', 'contributor', 'absolute_url', 'change')
9 changes: 9 additions & 0 deletions apps/moderation/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.urls import path

from apps.moderation.api import views

app_name = 'moderation'

urlpatterns = [
path('contributions/', views.ContentContributionAPIView.as_view()),
]
26 changes: 26 additions & 0 deletions apps/moderation/api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import TYPE_CHECKING

from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.moderation.api.serializers import ContentContributionSerializer
from apps.moderation.models.contribution import ContentContribution

if TYPE_CHECKING:
from rest_framework.request import Request


class ContentContributionAPIView(APIView):
"""API endpoint for content contribution."""

permission_classes = [permissions.IsAuthenticated]

def get(self, request: 'Request'):
"""Return the contents contributed"""
contributions = ContentContribution.objects.filter(contributor=request.user)
return (
Response([ContentContributionSerializer(result).data for result in contributions])
if contributions
else Response([])
)
9 changes: 8 additions & 1 deletion apps/moderation/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
SerializedModel = list[dict]


class SerializerJSONEncoder(JSONEncoder):
def default(self, obj):
if hasattr(obj, 'serialize'):
return obj.serialize()
return super().default(obj)


class SerializedObjectField(JSONField):
"""Model field for storing a serialized model instance."""

def __init__(self, *args, **kwargs):
"""Construct the field."""
kwargs['encoder'] = JSONEncoder
kwargs['encoder'] = SerializerJSONEncoder
kwargs['editable'] = False
super().__init__(*args, **kwargs)

Expand Down
16 changes: 15 additions & 1 deletion apps/moderation/models/contribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from django.db import models

from apps.moderation.fields import SerializedObjectField
from core.models import ExtendedModel


class ContentContribution(models.Model):
class ContentContribution(ExtendedModel):
"""A contribution to a change."""

contributor = models.ForeignKey(
Expand All @@ -28,3 +29,16 @@ class ContentContribution(models.Model):

def __str__(self) -> str:
return f'Contribution by {self.contributor} to {self.change} ({self.date_created})'

def get_absolute_url(self):
if self._state.adding:
return ''
return f'/users/{self.contributor.handle}/contributions/{self.pk}'


@classmethod
def get_serializer(self):
"""Return the serializer for ContentContribution"""
from apps.moderation.api.serializers import ContentContributionSerializer

return ContentContributionSerializer
27 changes: 16 additions & 11 deletions core/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import inspect
import logging
from pprint import pformat
from typing import TYPE_CHECKING, Any, ClassVar, Match, Optional, Pattern, Type, Union

import regex
Expand Down Expand Up @@ -99,6 +98,11 @@ def get_serializer(cls) -> type[Serializer]:
serializer = getattr(cls, 'serializer', None) or None
return serializer

@property
def absolute_url(self) -> str:
"""Return the model instance's absolute URL."""
return self.get_absolute_url()

@property
def admin_url(self) -> str:
"""Return the model instance's admin URL."""
Expand Down Expand Up @@ -191,16 +195,17 @@ def preprocess_html(self, html: str) -> str:

def serialize(self) -> dict:
"""Return the serialized model instance (dictionary)."""
try:
serialized_instance = self.serializer(self).data
except AttributeError as err:
logging.error(f'{err}')
serialized_instance = ModelSerializer(self).data
logging.debug(
f'Serialized {self.__class__.__name__.lower()}:\n'
f'{pformat(serialized_instance)}'
)
return serialized_instance
return self.get_serializer()(self).data
# try:
# serialized_instance = self.serializer(self).data
# except AttributeError as err:
# logging.error(f'{err}')
# serialized_instance = ModelSerializer(self).data
# logging.debug(
# f'Serialized {self.__class__.__name__.lower()}:\n'
# f'{pformat(serialized_instance)}'
# )
# return serialized_instance

@classmethod
def get_object_html(
Expand Down
4 changes: 0 additions & 4 deletions core/models/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,6 @@ def preprocess_html(self, html: str) -> str:
"""
return html

def serialize(self) -> dict:
"""Return the serialized model instance (dictionary)."""
return self.get_serializer()(self).data

@classmethod
def get_object_html(
cls,
Expand Down
1 change: 1 addition & 0 deletions core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def error(request: 'HttpRequest'):
path('api/forums/', include(_api('forums'), namespace='forums_api')),
path('api/home/', include(_api('home'), namespace='home_api')),
path('api/images/', include(_api('images'), namespace='images_api')),
path('api/moderation/', include(_api('moderation'), namespace='moderation_api')),
path('api/occurrences/', include(_api('occurrences'), namespace='occurrences_api')),
path('api/places/', include(_api('places'), namespace='places_api')),
path('api/propositions/', include(_api('propositions'), namespace='propositions_api')),
Expand Down
4 changes: 4 additions & 0 deletions frontend/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,13 @@ const GlobalNavbar: FC<GlobalNavbarProps> = ({ menuItems }: GlobalNavbarProps) =
accountControls = (
<NavDropdown id="accountDropdown" title={accountDropdownIcon} renderMenuOnMount alignRight>
<NavDropdown.Item href={`/users/${session.user.handle}`}>Profile</NavDropdown.Item>
<NavDropdown.Item href={`/users/${session.user.handle}/contributions`}>
My Contributions
</NavDropdown.Item>
<NavDropdown.Item href={`/users/${session.user.handle}/settings`}>
Settings
</NavDropdown.Item>
<Divider style={{ margin: "0.5rem 0" }} />
{(session.user.isSuperuser && (
<>
<Divider style={{ margin: "0.5rem 0" }} />
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/TodayInHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BigAnchor from "@/components/BigAnchor";
import { SerpModule } from "@/types/modules";
import { SerpModule } from "@/types/models";
import { Grid } from "@mui/material";
import { FC } from "react";
import ModuleUnionCard from "./cards/ModuleUnionCard";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/__tests__/TodayInHistory.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import TodayInHistory from "@/components/TodayInHistory";
import { Quote } from "@/types/modules";
import { Quote } from "@/types/models";
import { render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import mockRouter from "next-router-mock";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/cards/ModuleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Image, ModuleUnion, Source, Topic } from "@/types/modules";
import { Image, ModuleUnion, Source, Topic } from "@/types/models";
import { Card } from "@mui/material";
import { styled } from "@mui/material/styles";
import { CSSProperties } from "@mui/styles";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/cards/ModuleUnionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ModuleUnion, Topic } from "@/types/modules";
import { ModuleUnion, Topic } from "@/types/models";
import { Box } from "@mui/material";
import React, { FC } from "react";
import HTMLEllipsis from "react-lines-ellipsis/lib/html";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/details/ModuleDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropositionDetail from "@/components/propositions/PropositionDetail";
import { ModuleUnion } from "@/types/modules";
import { ModuleUnion } from "@/types/models";
import { useSession } from "next-auth/client";
import { FC } from "react";
import EntityDetail from "../entities/EntityDetail";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/details/ModuleLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ModuleModal from "@/components/details/ModuleModal";
import { ModuleUnion } from "@/types/modules";
import { ModuleUnion } from "@/types/models";
import { styled } from "@mui/material/styles";
import axios from "axios";
import { useRouter } from "next/router";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/details/ModuleModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ModuleDetail from "@/components/details/ModuleDetail";
import { GlobalTheme } from "@/pages/_app.page";
import { ModuleUnion } from "@/types/modules";
import { ModuleUnion } from "@/types/models";
import CloseIcon from "@mui/icons-material/Close";
import {
Button,
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/entities/EntityDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ModuleHTML from "@/components/details/ModuleHTML";
import { Entity } from "@/types/modules";
import { Entity } from "@/types/models";
import { FC } from "react";
import ImageCard from "../images/ImageCard";

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/images/ImageCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Image } from "@/types/modules";
import { Image } from "@/types/models";
import { styled } from "@mui/material/styles";
import { FC } from "react";
import HTMLEllipsis from "react-lines-ellipsis/lib/html";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/images/ImageDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Image } from "@/types/modules";
import { Image } from "@/types/models";
import { FC } from "react";
import ImageCard from "./ImageCard";

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/propositions/ArgumentSet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Argument } from "@/types/modules";
import { Argument } from "@/types/models";
import { TreeItem, TreeView } from "@mui/lab";
import { TreeItemProps } from "@mui/lab/TreeItem";
import { alpha, Theme } from "@mui/material";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/propositions/InlineProposition.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Proposition } from "@/types/modules";
import { Proposition } from "@/types/models";
import Link from "next/link";
import { FC } from "react";

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/propositions/OccurrenceDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ModuleHTML from "@/components/details/ModuleHTML";
import { Occurrence } from "@/types/modules";
import { Occurrence } from "@/types/models";
import { FC } from "react";
import ImageCard from "../images/ImageCard";
import TagList from "../topics/TagList";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/propositions/PropositionDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ModuleHTML from "@/components/details/ModuleHTML";
import TagList from "@/components/topics/TagList";
import { Proposition } from "@/types/modules";
import { Proposition } from "@/types/models";
import { Box } from "@mui/material";
import Slider from "@mui/material/Slider";
import { useSession } from "next-auth/client";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/quotes/QuoteDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ModuleHTML from "@/components/details/ModuleHTML";
import { Quote } from "@/types/modules";
import { Quote } from "@/types/models";
import { FC } from "react";
import ImageCard from "../images/ImageCard";
import TagList from "../topics/TagList";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/search/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SerpModule } from "@/types/modules";
import { SerpModule } from "@/types/models";
import Compress from "@mui/icons-material/Compress";
import {
Box,
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/sources/SourceDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Citation from "@/components/sources/Citation";
import { Source } from "@/types/modules";
import { Source } from "@/types/models";
import { FC } from "react";
import TagList from "../topics/TagList";

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/topics/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Topic } from "@/types/modules";
import { Topic } from "@/types/models";
import Chip from "@mui/material/Chip";
import { styled } from "@mui/material/styles";
import Link from "next/link";
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/topics/TagList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Topic } from "@/types/modules";
import { Topic } from "@/types/models";
import { FC } from "react";
import Tag from "./Tag";

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/topics/TopicDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ModuleCard from "@/components/cards/ModuleCard";
import ModuleHTML from "@/components/details/ModuleHTML";
import { Topic } from "@/types/modules";
import { Topic } from "@/types/models";
import { FC } from "react";
import HTMLEllipsis from "react-lines-ellipsis/lib/html";

Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/[...path].page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Layout from "@/components/Layout";
import { FlatPage as FlatPageType } from "@/types/modules";
import { FlatPage as FlatPageType } from "@/types/models";
import { Container, useMediaQuery } from "@mui/material";
import axios from "axios";
import { GetStaticPaths, GetStaticProps } from "next";
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/__tests__/search.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import SearchPage, { SearchProps } from "@/pages/search.page";
import type { Quote } from "@/types/modules";
import type { Quote } from "@/types/models";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import { Partial } from "@react-spring/types";
import { render, screen } from "@testing-library/react";
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/collections/[slug].page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ModuleUnionCard from "@/components/cards/ModuleUnionCard";
import Layout from "@/components/Layout";
import { Collection } from "@/types/modules";
import { Collection } from "@/types/models";
import ShareIcon from "@mui/icons-material/Share";
import { Box, Button, Container, useMediaQuery } from "@mui/material";
import Grid from "@mui/material/Grid";
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/collections/index.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axiosWithoutAuth from "@/axiosWithoutAuth";
import Layout from "@/components/Layout";
import PageHeader from "@/components/PageHeader";
import Pagination from "@/components/Pagination";
import { Collection } from "@/types/modules";
import { Collection } from "@/types/models";
import { CardContent } from "@mui/material";
import Grid from "@mui/material/Grid";
import { GetServerSideProps } from "next";
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/entities/[slug].page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axiosWithoutAuth from "@/axiosWithoutAuth";
import ModuleContainer from "@/components/details/ModuleContainer";
import ModuleDetail from "@/components/details/ModuleDetail";
import Layout from "@/components/Layout";
import { Entity } from "@/types/modules";
import { Entity } from "@/types/models";
import { Card, CardContent, CardHeader, styled } from "@mui/material";
import { GetStaticPaths, GetStaticProps } from "next";
import { NextSeo } from "next-seo";
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/entities/index.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ModuleUnionCard from "@/components/cards/ModuleUnionCard";
import Layout from "@/components/Layout";
import PageHeader from "@/components/PageHeader";
import Pagination from "@/components/Pagination";
import { Entity } from "@/types/modules";
import { Entity } from "@/types/models";
import Container from "@mui/material/Container";
import Grid from "@mui/material/Grid";
import { GetServerSideProps } from "next";
Expand Down
Loading