~linuxgoose/bocpress

ref: a72c4771fa8b0612594b4b98382b3e2605399074 bocpress/main/views/api.py -rw-r--r-- 5.6 KiB
a72c4771Jordan Robinson add tags to draft posts list 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import json

from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.views.generic.edit import FormView

from main import forms, models, util


def api_docs(request):
    return render(
        request,
        "main/api_docs.html",
        {
            "host": settings.CANONICAL_HOST,
            "protocol": util.get_protocol(),
        },
    )


class APIKeyReset(SuccessMessageMixin, LoginRequiredMixin, FormView):
    form_class = forms.ResetAPIKeyForm
    template_name = "main/api_key_reset.html"
    success_url = reverse_lazy("api_docs")
    success_message = "API key has been reset"

    def form_valid(self, form):
        super().form_valid(form)
        self.request.user.reset_api_key()
        return HttpResponseRedirect(self.get_success_url())


def _authenticate_token(request):
    """Verify request is authenticated with a token."""

    # check authorization header
    auth_header = request.headers.get("Authorization")
    if auth_header is None:
        return None

    # check auth header form
    if auth_header[:7] != "Bearer ":
        return None

    # check token's user
    token = auth_header[7:]
    users_from_token = models.User.objects.filter(api_key=token)
    if not users_from_token:
        return None

    return users_from_token.first()


@require_http_methods(["POST", "GET"])
@csrf_exempt
def api_posts(request):
    user = _authenticate_token(request)
    if not user:
        return JsonResponse({"ok": False, "error": "Not authorized."}, status=403)

    # handle GET case
    if request.method == "GET":
        post_list = models.Post.objects.filter(owner=user)
        post_list = [
            {
                "title": p.title,
                "slug": p.slug,
                "body": p.body,
                "published_at": p.published_at,
                "url": util.get_protocol() + p.get_absolute_url(),
            }
            for p in post_list
        ]
        return JsonResponse(
            {
                "ok": True,
                "post_list": post_list,
            }
        )

    # POST case - validate input data
    try:
        data = json.loads(request.body.decode("utf-8"))
    except json.JSONDecodeError:
        return JsonResponse({"ok": False, "message": "Input data invalid."}, status=400)
    form = forms.APIPost(data)
    if not form.is_valid():
        return JsonResponse({"ok": False, "message": "Input data invalid."}, status=400)
    if "title" not in data:
        return JsonResponse(
            {"ok": False, "message": "Title field is required."}, status=400
        )

    # POST case - create post
    slug = util.create_post_slug(data["title"], user)
    published_at = None
    if "published_at" in data:
        published_at = data["published_at"]
    body = ""
    if "body" in data:
        body = data["body"]
    post = models.Post.objects.create(
        owner=user, title=data["title"], slug=slug, body=body, published_at=published_at
    )

    return JsonResponse(
        {"ok": True, "slug": slug, "url": util.get_protocol() + post.get_absolute_url()}
    )


@require_http_methods(["PATCH", "GET", "DELETE"])
@csrf_exempt
def api_post(request, slug):
    user = _authenticate_token(request)
    if not user:
        return JsonResponse({"ok": False, "error": "Not authorized."}, status=403)

    # validate input data
    if request.method == "PATCH":
        try:
            data = json.loads(request.body.decode("utf-8"))
        except json.JSONDecodeError:
            return JsonResponse(
                {"ok": False, "message": "Input data invalid."}, status=400
            )
        form = forms.APIPost(data)
        if not form.is_valid():
            return JsonResponse(
                {"ok": False, "message": "Input data invalid."}, status=400
            )

    # get post
    post_list = models.Post.objects.filter(slug=slug, owner=user)
    if not post_list:
        return JsonResponse({"ok": False, "error": "Not found."}, status=404)
    post = post_list.first()
    if post.owner != user:
        return JsonResponse({"ok": False, "error": "Not allowed."}, status=403)

    # delete case
    if request.method == "DELETE":
        post.delete()
        return JsonResponse(
            {
                "ok": True,
            }
        )

    # retrieve case
    if request.method == "GET":
        return JsonResponse(
            {
                "ok": True,
                "url": util.get_protocol() + post.get_absolute_url(),
                "slug": post.slug,
                "title": post.title,
                "body": post.body,
                "published_at": post.published_at,
            }
        )

    # update post
    if request.method == "PATCH":
        if "title" in data:
            post.title = form.cleaned_data["title"]
        if "slug" in data:
            post.slug = util.create_post_slug(
                form.cleaned_data["slug"], user, post=post
            )
        if "body" in data:
            post.body = util.remove_control_chars(form.cleaned_data["body"])
        if "published_at" in data:
            post.published_at = form.cleaned_data["published_at"]
        post.save()
        return JsonResponse(
            {
                "ok": True,
                "slug": post.slug,
                "url": util.get_protocol() + post.get_absolute_url(),
            }
        )