class NovelTools(View): @method_decorator(get_novel_by_path) def get(self, request, *args, **kwargs): novel = request.novel return JsonResponse( { 'title': novel.title, 'lore': novel.lore, 'content': novel.content, 'uploadedAt': novel.uploadedAt.isoformat(), 'favorite': request.fb_user.favorites.filter(pk=novel.pk).exists(), 'lang': novel.lang }, charset='utf-8') @method_decorator(get_novel_by_path) @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'You have to be logged in to edit novels', 'You don\'t have permission to edit this novel')) def patch(self, request, *args, **kwargs): fields = { 'title': str, 'lore': str, 'content': str, 'lang': str, 'private': bool } novel = request.novel try: body = json.loads(request.body.decode('utf-8')) except JSONDecodeError: return JsonResponse({'error': 'Json parse error'}, status=400) for p in fields.keys(): if p in body and type(body[p]) == fields[p] and ( p != 'lang' or p in Novel._meta.get_field('lang').choices): setattr(novel, p, body[p]) novel.save() return JsonResponse({ 'title': novel.title, 'path': novel.path, 'lore': novel.lore, 'content': novel.content, 'lang': novel.lang, 'private': novel.private }) @method_decorator(get_novel_by_path) @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'You have to be logged in to edit novels', 'You don\'t have permission to edit this novel')) def delete(self, request, *args, **kwargs): request.novel.delete() return JsonResponse({"success": "Deleted successfully"})
class IntroductionView(View): @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'You have to be logged in to edit introduction', 'You don\'t have permission to edit introduction')) def post(self, request, *args, **kwargs): try: body = json.loads(request.body.decode('utf-8')) except JSONDecodeError: return JsonResponse({'error': 'Json parse error'}, status=400) if not ('introduction' in body and isinstance(body['introduction'], str)): return JsonResponse({'error': 'introduction property missing'}, status=400) if not ('lang' in body and isinstance(body['introduction'], str)): return JsonResponse({'error': 'lang property missing'}, status=400) if Introduction.objects.filter(key=body['lang']).exists(): intro = Introduction.objects.get(key=body['lang']) else: intro = Introduction.objects.create(key=body['lang']) intro.value = body['introduction'] intro.save() return JsonResponse({'introduction': intro.value}) def get(self, request, *args, **kwargs): lang: str = request.GET.get('lang', 'EN') try: intro = Introduction.objects.get(key=lang).value except: intro = 'Sorry, I don\'t use this language ¯\\_( ͡° ͜ʖ ͡°)_/¯' return JsonResponse({'introduction': intro})
class DeleteAll(View): @method_decorator(get_user_by_id) @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'Log in to do this', 'You are not admin')) def delete(self, request, *args, **kwargs): Comment.objects.filter(sender=request.fb_user_byId).delete() return JsonResponse({"success": "Deleted successfully"})
class Banned(View): @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'Log in to do this', 'You are not admin')) def get(self, request, *args, **kwargs): resp: list[dict[str, any]] = [] for u in User.objects.filter(banned=True): resp.append({"name": u.name, "id": u.id}) return JsonResponse(resp, safe=False)
class Recent(View): @method_decorator( permission_needed(lambda request: request.fb_user.isAnonymous, 'Log in to do this', 'You are not admin')) def get(self, request, *args, **kwargs): resp: list[dict[str, any]] = [] if request.fb_user.isAdmin: comments = Comment.objects.filter( parentComment=None, sender__isAdmin=False).order_by('-writtenAt')[:5] else: comments = Comment.objects.filter( sender=request.fb_user).order_by('-writtenAt')[:5] for c in comments: found = False for n in resp: if n['title'] == c.novel.title: found = True n['comments'].append({ 'content': c.content, 'senderName': c.sender.name, 'writtenAt': c.writtenAt, 'id': c.id, 'recipientName': c.recipient.name if c.recipient else None, 'isReply': c.parentComment is not None }) break if found: continue resp.append({ 'title': c.novel.title, 'path': c.novel.path, 'comments': [{ 'content': c.content, 'senderName': c.sender.name, 'writtenAt': c.writtenAt, 'id': c.id, 'recipientName': c.recipient.name if c.recipient else None, 'isReply': c.parentComment is not None }] }) return JsonResponse(resp, safe=False)
class UserFavorites(View): @method_decorator( permission_needed(lambda request: request.fb_user.isAnonymous, 'Log in to have novels as favorite', "Log in with a non-Anonymous account")) def get(self, request, *args, **kwargs): resp = [] for fav in request.fb_user.favorites.all(): resp.append({'title': fav.title, 'path': fav.path}) return JsonResponse(resp, safe=False, charset='utf-8')
class Ban(View): @method_decorator(get_user_by_id) @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'Log in to do this', 'You are not admin')) def post(self, request, *args, **kwargs): user = request.fb_user_byId user.banned = True user.save() return JsonResponse( {'success': f'Successfully banned {user.name} from commenting'})
class DeleteCommentById(View): @method_decorator(get_comment_by_id) @method_decorator( permission_needed( lambda request: not (request.fb_user == request.comment.sender or request.fb_user.isAdmin), 'You have to be logged in to delete comments', 'You cannot delete this comment')) def delete(self, request, *args, **kwargs): request.comment.delete() return JsonResponse(getCommentsForNovel(request.comment.novel, request.fb_user), safe=False)
class UserView(View): def get(self, request, *args, **kwargs): user = request.fb_user print(user) return JsonResponse({ 'stranger': not user.isAuthenticated, 'anonim': user.isAnonymous, 'authenticated': user.isAuthenticated and not user.isAnonymous and not user.isAdmin, 'admin': user.isAdmin, 'name': user.name }) @method_decorator( permission_needed(lambda request: request.fb_user.isAnonymous, 'Log in to change your name', 'Anonymous accounts can\'t change name')) def put(self, request, *args, **kwargs): decoded = json.loads(request.body) if 'name' not in decoded or type(decoded['name']) != str: return JsonResponse({'error': 'name parameter not found'}, status=400) user = request.fb_user user.name = decoded['name'] user.save() return JsonResponse({'name': user.name}) @method_decorator( permission_needed(lambda request: request.fb_user.isAnonymous, 'Log in to delete your account', 'Anonymous accounts can\'t delete themselves')) def delete(self, request, *args, **kwargs): request.fb_user.delete() return JsonResponse({'success': 'Deleted successfully'})
class NovelFavoriteToggle(View): @method_decorator(get_novel_by_path) @method_decorator( permission_needed(lambda request: request.fb_user.isAnonymous, 'Log in to mark novels as favorite', "Log in with a non-Anonymous account")) def post(self, request, *args, **kwargs): novel = request.novel favs = request.fb_user.favorites if favs.filter(pk=novel.pk).exists(): favs.remove(novel) return JsonResponse({'favorite': False}) else: favs.add(novel) return JsonResponse({'favorite': True}) @method_decorator(get_novel_by_path) @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'Log in to see this value', 'You have to be admin to see this value')) def get(self, request, *args, **kwargs): return JsonResponse({'favorites': len(request.novel.user_set.all())})
class LikeComment(View): @method_decorator(get_comment_by_id) @method_decorator( permission_needed( lambda request: not request.fb_user.isAuthenticated or request. fb_user.banned, 'You have to be logged in - even with an anonymous account - to like a comment', 'You are banned from writing comments')) def post(self, request, *args, **kwargs): if request.comment.liked.filter(id=request.fb_user.id).exists(): request.comment.liked.remove(request.fb_user) else: request.comment.liked.add(request.fb_user) request.comment.save() return JsonResponse(getCommentsForNovel(request.comment.novel, request.fb_user), safe=False)
class NewUpload(View): @method_decorator( permission_needed(lambda request: not request.fb_user.isAdmin, 'You have to be logged in to upload novels', 'You don\'t have permission to upload novels')) def post(self, request, *args, **kwargs): fn = 'noveldoc' try: d = Document(request.FILES[fn]) except MultiValueDictKeyError: return JsonResponse({"error": f"No file with name: {fn}"}, status=400) except BadZipFile: return JsonResponse({"error": "Wrong file"}, status=400) if len(d.paragraphs) < 2: return JsonResponse({"error": "Wrong file"}, status=400) novel = None try: novel = Novel.objects.create(title=d.paragraphs[0].text, private=True) except IntegrityError: n = Novel.objects.get(title=d.paragraphs[0].text) if n.private: n.delete() novel = Novel.objects.create(title=d.paragraphs[0].text, private=True) else: return JsonResponse({"error": "Not unique title"}, status=400) # string.join won't work content = '' padding = '\n' for l in d.paragraphs[1:]: content += l.text + padding content = content[:-len(padding)] novel.content = content novel.save() return JsonResponse({ 'title': novel.title, 'path': novel.path, 'filename': request.FILES[fn].name })
class ReplyComment(View): @method_decorator(get_comment_by_id) @method_decorator( permission_needed( lambda request: not request.fb_user.isAuthenticated or request. fb_user.banned, 'You have to be logged in - even with an anonymous account - to write a comment', 'You are banned from writing comments')) def post(self, request, *args, **kwargs): body = json.loads(request.body.decode('utf-8')) if "content" not in body: return JsonResponse({"error": "Bad input"}, status=400) Comment.objects.create( content=body["content"], sender=request.fb_user, parentComment=request.comment, novel=request.comment.novel, recipient=User.objects.get( id=body["recipient"]) if "recipient" in body else None) return JsonResponse(getCommentsForNovel(request.comment.novel, request.fb_user), safe=False)