Coverage for src/django_resume/projects.py: 41%
85 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-23 13:16 +0200
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-23 13:16 +0200
1from typing import Type, Any
3from django import forms
5from .plugins import ListPlugin, ListItemFormMixin, ListTemplates, ListInline
8class ProjectItemForm(ListItemFormMixin, forms.Form):
9 title = forms.CharField(widget=forms.TextInput())
10 url = forms.URLField(widget=forms.URLInput(), required=False, assume_scheme="https")
11 description = forms.CharField(widget=forms.Textarea())
12 badges = forms.CharField(widget=forms.TextInput(), required=False)
13 position = forms.IntegerField(widget=forms.NumberInput(), required=False)
15 def __init__(self, *args, **kwargs):
16 super().__init__(*args, **kwargs)
17 self.set_initial_badges()
18 self.set_initial_position()
20 @staticmethod
21 def get_initial() -> dict[str, Any]:
22 """Just some default values."""
23 return {
24 "title": "Project Title",
25 "url": "https://example.com/project/",
26 "description": "description",
27 "badges": "badges",
28 }
30 def set_context(self, item: dict, context: dict[str, Any]) -> dict[str, Any]:
31 context["project"] = {
32 "id": item["id"],
33 "url": item["url"],
34 "title": item["title"],
35 "description": item["description"],
36 "badges": item["badges"],
37 "edit_url": context["edit_url"],
38 "delete_url": context["delete_url"],
39 }
40 return context
42 def set_initial_badges(self):
43 """Transform the list of badges into a comma-separated string."""
44 if "badges" in self.initial and isinstance(self.initial["badges"], list):
45 self.initial["badges"] = ",".join(self.initial["badges"])
47 @staticmethod
48 def get_max_position(items):
49 """Return the maximum position value from the existing items."""
50 positions = [item.get("position", 0) for item in items]
51 return max(positions) if positions else -1
53 def set_initial_position(self):
54 """Set the position to the next available position."""
55 if "position" not in self.initial:
56 self.initial["position"] = self.get_max_position(self.existing_items) + 1
58 def clean_title(self):
59 title = self.cleaned_data["title"]
60 if title == "Senor Developer":
61 print("No Senor! Validation Error!")
62 raise forms.ValidationError("No Senor!")
63 return title
65 def clean_badges(self):
66 badges = self.cleaned_data.get("badges", "")
67 # Split the comma-separated values and strip any extra spaces
68 badge_list = [badge.strip() for badge in badges.split(",")]
69 return badge_list
71 def clean_position(self):
72 position = self.cleaned_data.get("position", 0)
73 if position < 0:
74 raise forms.ValidationError("Position must be a positive integer.")
75 for item in self.existing_items:
76 if item["id"] == self.cleaned_data["id"]:
77 # updating the existing item, so we can skip checking its position
78 continue
79 if item.get("position") == position:
80 max_position = self.get_max_position(self.existing_items)
81 raise forms.ValidationError(
82 f"Position must be unique - take {max_position + 1} instead."
83 )
84 return position
87class ProjectFlatForm(forms.Form):
88 title = forms.CharField(widget=forms.TextInput(), required=False, max_length=50)
90 @staticmethod
91 def set_context(item: dict, context: dict[str, Any]) -> dict[str, Any]:
92 context["projects"] = {"title": item.get("title", "")}
93 context["projects"]["edit_flat_url"] = context["edit_flat_url"]
94 return context
97class ProjectsForContext:
98 def __init__(
99 self,
100 *,
101 title: str,
102 ordered_entries: list[dict],
103 templates: ListTemplates,
104 add_item_url: str,
105 edit_flat_url: str,
106 edit_flat_post_url: str,
107 ):
108 self.title = title
109 self.ordered_entries = ordered_entries
110 self.templates = templates
111 self.add_item_url = add_item_url
112 self.edit_flat_url = edit_flat_url
113 self.edit_flat_post_url = edit_flat_post_url
116class ProjectsPlugin(ListPlugin):
117 name: str = "projects"
118 verbose_name: str = "Projects"
119 inline: ListInline
120 templates = ListTemplates(
121 main="django_resume/plain/projects.html",
122 flat="django_resume/plain/projects_flat.html",
123 flat_form="django_resume/plain/projects_flat_form.html",
124 item="django_resume/plain/projects_item.html",
125 item_form="django_resume/plain/projects_item_form.html",
126 )
128 @staticmethod
129 def get_form_classes() -> dict[str, Type[forms.Form]]:
130 return {"item": ProjectItemForm, "flat": ProjectFlatForm}
132 @staticmethod
133 def items_ordered_by_position(items, reverse=False):
134 return sorted(items, key=lambda item: item.get("position", 0), reverse=reverse)
136 def get_context(
137 self, plugin_data, person_pk, *, context: dict[str, Any]
138 ) -> ProjectsForContext:
139 ordered_entries = self.items_ordered_by_position(
140 plugin_data.get("items", []), reverse=True
141 )
142 if context.get("show_edit_button", False):
143 # if there should be edit buttons, add the edit URLs to each entry
144 for entry in ordered_entries:
145 entry["edit_url"] = self.inline.get_edit_item_url(
146 person_pk, item_id=entry["id"]
147 )
148 entry["delete_url"] = self.inline.get_delete_item_url(
149 person_pk, item_id=entry["id"]
150 )
151 print("edit flat post: ", self.inline.get_edit_flat_post_url(person_pk))
152 projects = ProjectsForContext(
153 title=plugin_data.get("flat", {}).get("title", self.verbose_name),
154 ordered_entries=ordered_entries,
155 templates=self.templates,
156 add_item_url=self.inline.get_edit_item_url(person_pk),
157 edit_flat_url=self.inline.get_edit_flat_url(person_pk),
158 edit_flat_post_url=self.inline.get_edit_flat_post_url(person_pk),
159 )
160 return projects