Coverage for website/views/AuthorView.py: 81%

169 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-09-13 15:29 -0300

1from django.contrib import messages 

2from django.contrib.auth import update_session_auth_hash 

3from django.forms import inlineformset_factory 

4from django.shortcuts import get_object_or_404, redirect, render 

5 

6from website.forms.EditAuthorForm import ( 

7 EditAuthorForm, 

8 GraduationForm, 

9 JobForm, 

10 SocialMediaForm, 

11 UserChangeForm, 

12) 

13from website.models import User 

14from website.models.__init__ import ACADEMIC_LEVEL, SOCIAL_MEDIA 

15from website.models.AuthorModel import Author 

16from website.models.AuthorSocialMediaModel import SocialMedia 

17from website.models.GraduationsModel import Graduation 

18from website.models.JobsModel import Job 

19 

20 

21def view_author_page(request, slug): 

22 author = get_object_or_404(Author, author_url_slug=slug) 

23 context = { 

24 "author": author, 

25 "author_connected": False, 

26 "social_media_index": SOCIAL_MEDIA, 

27 "graduations_level": ACADEMIC_LEVEL, 

28 } 

29 if request.user != author.user: 

30 return render( 

31 request, template_name="author/author.html", context=context, status=200 

32 ) 

33 context["author_connected"] = True 

34 return render( 

35 request, template_name="author/author.html", context=context, status=200 

36 ) 

37 

38 

39def edit_author_profile(request, slug): 

40 author = get_object_or_404(Author, author_url_slug=slug) 

41 author_social_media = author.social_media.all() 

42 form = EditAuthorForm(instance=author) 

43 user_form = UserChangeForm(instance=request.user) 

44 social_forms = [] 

45 for social in author_social_media: 

46 social_forms.append(SocialMediaForm(instance=social)) 

47 social_empty_form = SocialMediaForm() 

48 send_message = False 

49 

50 # create formset factory here (safe even if GraduationFormSet defined later) 

51 GraduationFormSetLocal = inlineformset_factory( 

52 Author, Graduation, form=GraduationForm, extra=0, can_delete=True 

53 ) 

54 JobFormSetLocal = inlineformset_factory( 

55 Author, Job, form=JobForm, extra=0, can_delete=True 

56 ) 

57 

58 if request.POST: 

59 # rebind user and author forms with POST data 

60 user_form = UserChangeForm(request.POST, instance=request.user) 

61 author_form = EditAuthorForm(request.POST, request.FILES, instance=author) 

62 

63 # instantiate formset with POST (and FILES) and try to detect prefix 

64 prefix = None 

65 for k in request.POST.keys(): 

66 if k.endswith("-TOTAL_FORMS") and "gradu" in k.lower(): 

67 prefix = k.rsplit("-TOTAL_FORMS", 1)[0] 

68 break 

69 if prefix is None: 

70 for k in request.POST.keys(): 

71 if k.endswith("-TOTAL_FORMS"): 

72 prefix = k.rsplit("-TOTAL_FORMS", 1)[0] 

73 break 

74 

75 # try to detect graduation vs job prefix separately 

76 grad_prefix = None 

77 job_prefix = None 

78 for k in request.POST.keys(): 

79 if k.endswith("-TOTAL_FORMS"): 

80 low = k.lower() 

81 if "gradu" in low: 

82 grad_prefix = k.rsplit("-TOTAL_FORMS", 1)[0] 

83 if "job" in low or "jobs" in low: 

84 job_prefix = k.rsplit("-TOTAL_FORMS", 1)[0] 

85 

86 if grad_prefix: 

87 graduation_formset = GraduationFormSetLocal( 

88 request.POST, request.FILES, instance=author, prefix=grad_prefix 

89 ) 

90 else: 

91 graduation_formset = GraduationFormSetLocal( 

92 request.POST, request.FILES, instance=author 

93 ) 

94 

95 if job_prefix: 

96 job_formset = JobFormSetLocal( 

97 request.POST, request.FILES, instance=author, prefix=job_prefix 

98 ) 

99 else: 

100 job_formset = JobFormSetLocal(request.POST, request.FILES, instance=author) 

101 

102 # (debug logs removed) 

103 

104 # rebind social forms with POST 

105 social_forms = [] 

106 for social in author_social_media: 

107 social_forms.append(SocialMediaForm(request.POST, instance=social)) 

108 

109 author_request_post = check_request_post(request) 

110 if author_request_post is not None: 

111 if author.image != "" and author_request_post["image"] is not None: 

112 author.image.delete(save=True) 

113 author.image = author_request_post["image"] 

114 

115 # validate forms 

116 forms_ok = True 

117 

118 # (debug logs removed) 

119 

120 # username conflict check 

121 username_conflict = False 

122 if author_request_post: 

123 username_conflict = bool(author_request_post.get("check_username_request")) 

124 if not user_form.is_valid() or username_conflict: 

125 forms_ok = False 

126 if username_conflict: 

127 messages.error(request, "Nome de usuário já está em uso.") 

128 

129 if not author_form.is_valid(): 

130 forms_ok = False 

131 

132 # validate graduation formset 

133 if not graduation_formset.is_valid(): 

134 forms_ok = False 

135 

136 # validate job formset 

137 if not job_formset.is_valid(): 

138 forms_ok = False 

139 

140 if forms_ok: 

141 # save user (handle password: preserve original if empty) 

142 original_password = request.user.password 

143 user = user_form.save(commit=False) 

144 pw = user_form.cleaned_data.get("password") 

145 if pw: 

146 user.set_password(pw) 

147 # keep the current session authenticated after a password change 

148 try: 

149 update_session_auth_hash(request, user) 

150 except Exception: 

151 # be conservative: if session update fails, continue and let 

152 # Django's auth system handle the next request 

153 pass 

154 else: 

155 # preserve original hashed password 

156 user.password = original_password 

157 user.save() 

158 

159 # save author 

160 author = author_form.save() 

161 

162 # update social media entries 

163 if update_social_media(request, author_social_media): 

164 send_message = True 

165 # create new social media if requested 

166 if ( 

167 author_request_post 

168 and author_request_post.get("new_social_addition") 

169 and not any(author_request_post.get("exclude_social_media", [])) 

170 ): 

171 create_social_media(request, author_request_post) 

172 send_message = True 

173 # exclude if requested 

174 if author_request_post and any( 

175 author_request_post.get("exclude_social_media", []) 

176 ): 

177 exclude_social_media(request, author) 

178 send_message = True 

179 

180 # save graduation formset (instance already saved) 

181 graduation_formset.instance = author 

182 graduation_formset.save() 

183 # save jobs 

184 job_formset.instance = author 

185 job_formset.save() 

186 send_message = True 

187 

188 if send_message: 

189 messages.success(request, "Dados atualizados com sucesso.") 

190 return redirect("author", slug=author.author_url_slug) 

191 else: 

192 # render page with errors (no redirect) 

193 context = { 

194 "socialEmptyForm": social_empty_form, 

195 "userForm": user_form, 

196 "authorForm": author_form, 

197 "socialForms": social_forms, 

198 "academic_levels": ACADEMIC_LEVEL, 

199 "graduation_formset": graduation_formset, 

200 "job_formset": job_formset, 

201 } 

202 return render( 

203 request, 

204 template_name="edit-author/edit-author.html", 

205 context=context, 

206 ) 

207 else: 

208 # GET: provide an empty/loaded formset instance 

209 graduation_formset = GraduationFormSetLocal(instance=author) 

210 job_formset = JobFormSetLocal(instance=author) 

211 

212 context = { 

213 "socialEmptyForm": social_empty_form, 

214 "userForm": user_form, 

215 "authorForm": form, 

216 "socialForms": social_forms, 

217 "academic_levels": ACADEMIC_LEVEL, 

218 "graduation_formset": graduation_formset, 

219 "job_formset": job_formset, 

220 } 

221 return render( 

222 request, template_name="edit-author/edit-author.html", context=context 

223 ) 

224 

225 

226def check_request_post(request): 

227 author_post_request_data = None 

228 if request.POST: 

229 author_post_request_data = { 

230 "username": request.POST["username"], 

231 "name": request.POST["author_name"], 

232 "check_username_request": Author.objects.filter( 

233 user__username=request.POST["username"] 

234 ) 

235 .exclude(user__id=request.user.id) 

236 .first(), 

237 "image": request.FILES.get("image", None), 

238 "new_social_addition": len(request.POST.getlist("social_media_profile")) 

239 > len( 

240 Author.objects.get( 

241 user__username=request.POST["username"] 

242 ).social_media.all() 

243 ), 

244 "exclude_social_media": request.POST.getlist("exclude-social"), 

245 } 

246 

247 return author_post_request_data 

248 

249 

250def check_user_form(request, author): 

251 user_form = UserChangeForm(request.POST, instance=request.user) 

252 author_user = check_request_post(request) 

253 username_free = author_user["check_username_request"] != author.user.username 

254 if ( 

255 user_form.is_valid() 

256 and author_user["username"] != author.user.username 

257 and username_free 

258 ): 

259 user_author = get_object_or_404(User, id=author.user.id) 

260 user_author.username = author_user["username"] 

261 user_author.save() 

262 return username_free 

263 

264 

265def check_author_form(request, author): 

266 author_form = EditAuthorForm(request.POST, request.FILES, instance=author) 

267 check_post = check_request_post(request) 

268 if author_form.is_valid(): 

269 author.author_name = check_post["name"] 

270 author.save() 

271 return True 

272 return False 

273 

274 

275def update_social_media(request, author_social_media): 

276 social_media_request_post = list( 

277 zip( 

278 request.POST.getlist("social_media"), 

279 request.POST.getlist("social_media_profile"), 

280 ) 

281 ) 

282 updated = False 

283 for i in range(len(author_social_media)): 

284 if ( 

285 author_social_media[i].social_media != int(social_media_request_post[i][0]) 

286 ) or ( 

287 author_social_media[i].social_media_profile 

288 != social_media_request_post[i][1] 

289 ): 

290 author_social_media[i].social_media = social_media_request_post[i][0] 

291 author_social_media[i].social_media_profile = social_media_request_post[i][ 

292 1 

293 ] 

294 author_social_media[i].save() 

295 updated = True 

296 return updated 

297 

298 

299def create_social_media(request, author_request_post): 

300 social_media_request_post = list( 

301 zip( 

302 request.POST.getlist("social_media"), 

303 request.POST.getlist("social_media_profile"), 

304 ) 

305 ) 

306 author = Author.objects.get(user__username=author_request_post["username"]) 

307 social = author.social_media.all() 

308 

309 for i in range(len(social), len(social_media_request_post)): 

310 new_social = SocialMedia.objects.create( 

311 user_social_media=author, 

312 social_media=social_media_request_post[i][0], 

313 social_media_profile=social_media_request_post[i][1], 

314 ) 

315 new_social.save() 

316 author.social_media.add(new_social) 

317 

318 

319def exclude_social_media(request, author): 

320 exclusions = check_request_post(request)["exclude_social_media"] 

321 for exclude_request in exclusions: 

322 if exclude_request != "": 

323 # directly delete the matched social media entry 

324 author.social_media.get(social_media=exclude_request).delete() 

325 

326 

327def set_graduation(): 

328 pass 

329 

330 

331def edit_author(request, author_slug=None): 

332 """Wrapper to keep compatibility: delegate to edit_author_profile. 

333 

334 If no author_slug is provided, use the logged-in user's author slug. 

335 """ 

336 if not author_slug: 

337 if hasattr(request, "user") and getattr(request.user, "author", None): 

338 slug = request.user.author.author_url_slug 

339 else: 

340 # nothing sensible to edit; redirect to home 

341 return redirect("/") 

342 else: 

343 slug = author_slug 

344 return edit_author_profile(request, slug)