Coverage for src/django_resume/projects.py: 41%

1 from typing import Type, Any

2

3 from django import forms

4

5 from .plugins import ListPlugin, ListItemFormMixin, ListTemplates, ListInline

6

7

8 class 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)

14

15 def __init__(self, *args, **kwargs):

16 super().__init__(*args, **kwargs)

17 self.set_initial_badges()

18 self.set_initial_position()

19

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 }

29

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

41

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"])

46

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

52

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

57

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

64

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

70

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

85

86

87 class ProjectFlatForm(forms.Form):

88 title = forms.CharField(widget=forms.TextInput(), required=False, max_length=50)

89

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

95

96

97 class 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

114

115

116 class 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 )

127

128 @staticmethod

129 def get_form_classes() -> dict[str, Type[forms.Form]]:

130 return {"item": ProjectItemForm, "flat": ProjectFlatForm}

131

132 @staticmethod

133 def items_ordered_by_position(items, reverse=False):

134 return sorted(items, key=lambda item: item.get("position", 0), reverse=reverse)

135

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