Coverage for src/django_resume/plugins/projects.py: 47%

68 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-10-13 13:17 +0200

1import json 

2 

3from typing import Type, Any 

4 

5from django import forms 

6 

7from .base import ListPlugin, ListItemFormMixin, ListTemplates, ListInline 

8 

9 

10class ProjectItemForm(ListItemFormMixin, forms.Form): 

11 title = forms.CharField(widget=forms.TextInput()) 

12 url = forms.URLField(widget=forms.URLInput(), required=False, assume_scheme="https") 

13 description = forms.CharField(widget=forms.Textarea()) 

14 initial_badges = ["Some Badge", "Another Badge"] 

15 badges = forms.JSONField( 

16 widget=forms.TextInput(), required=False, initial=initial_badges 

17 ) 

18 position = forms.IntegerField(widget=forms.NumberInput(), required=False) 

19 

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

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

22 self.set_initial_position() 

23 

24 def badges_as_json(self): 

25 """ 

26 Return the initial badges which should already be a normal list of strings 

27 or the initial_badged list for the first render of the form encoded as json. 

28 """ 

29 existing_badges = self.initial.get("badges") 

30 if existing_badges is not None: 

31 return json.dumps(existing_badges) 

32 return json.dumps(self.initial_badges) 

33 

34 @staticmethod 

35 def get_initial() -> dict[str, Any]: 

36 """Just some default values.""" 

37 return { 

38 "title": "Project Title", 

39 "url": "https://example.com/project/", 

40 "description": "description", 

41 "badges": ProjectItemForm.initial_badges, 

42 } 

43 

44 def set_context(self, item: dict, context: dict[str, Any]) -> dict[str, Any]: 

45 context["project"] = { 

46 "id": item["id"], 

47 "url": item["url"], 

48 "title": item["title"], 

49 "description": item["description"], 

50 "badges": item["badges"], 

51 "edit_url": context["edit_url"], 

52 "delete_url": context["delete_url"], 

53 } 

54 return context 

55 

56 def set_initial_badges(self): 

57 """Transform the list of badges into a comma-separated string.""" 

58 if "badges" in self.initial and isinstance(self.initial["badges"], list): 

59 self.initial["badges"] = ",".join(self.initial["badges"]) 

60 

61 @staticmethod 

62 def get_max_position(items): 

63 """Return the maximum position value from the existing items.""" 

64 positions = [item.get("position", 0) for item in items] 

65 return max(positions) if positions else -1 

66 

67 def set_initial_position(self): 

68 """Set the position to the next available position.""" 

69 if "position" not in self.initial: 

70 self.initial["position"] = self.get_max_position(self.existing_items) + 1 

71 

72 def clean_title(self): 

73 title = self.cleaned_data["title"] 

74 if title == "Senor Developer": 

75 print("No Senor! Validation Error!") 

76 raise forms.ValidationError("No Senor!") 

77 return title 

78 

79 def clean_position(self): 

80 position = self.cleaned_data.get("position", 0) 

81 if position < 0: 

82 raise forms.ValidationError("Position must be a positive integer.") 

83 for item in self.existing_items: 

84 if item["id"] == self.cleaned_data["id"]: 

85 # updating the existing item, so we can skip checking its position 

86 continue 

87 if item.get("position") == position: 

88 max_position = self.get_max_position(self.existing_items) 

89 raise forms.ValidationError( 

90 f"Position must be unique - take {max_position + 1} instead." 

91 ) 

92 return position 

93 

94 

95class ProjectFlatForm(forms.Form): 

96 title = forms.CharField( 

97 widget=forms.TextInput(), required=False, max_length=50, initial="Projects" 

98 ) 

99 

100 @staticmethod 

101 def set_context(item: dict, context: dict[str, Any]) -> dict[str, Any]: 

102 context["projects"] = {"title": item.get("title", "")} 

103 context["projects"]["edit_flat_url"] = context["edit_flat_url"] 

104 return context 

105 

106 

107class ProjectsPlugin(ListPlugin): 

108 name: str = "projects" 

109 verbose_name: str = "Projects" 

110 inline: ListInline 

111 templates = ListTemplates( 

112 main="django_resume/projects/plain/content.html", 

113 flat="django_resume/projects/plain/flat.html", 

114 flat_form="django_resume/projects/plain/flat_form.html", 

115 item="django_resume/projects/plain/item.html", 

116 item_form="django_resume/projects/plain/item_form.html", 

117 ) 

118 flat_form_class = ProjectFlatForm 

119 

120 @staticmethod 

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

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