Skip to content

Resources

LoginApi

Bases: Resource

This class is a subclass of the Resource class from the Flask-RESTful library. It handles requests against the Snippet model to api/auth/login

Source code in resources/auth.py
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
class LoginApi(Resource):
    """This class is a subclass of the Resource class from the Flask-RESTful library. It handles requests against the
    Snippet model to `api/auth/login`"""

    @staticmethod
    def post(self):
        """Authenticate a User object against the User model.

        Yields:
            Check the email.
            Check the password.

        Args:
            self: Reference the class itself

        Flags:
            Errors and returns status code with error message,
                200, otherwise.
        Returns:
            {dict}: JSON Flask Response
                with an access token and a username.
                sets a refresh-cookie in headers.
        """

        try:
            body = request.get_json()
            user = User.objects.get(email=body.get("email"))
            authorized = user.check_password(body.get("password"))
            if not authorized:
                raise UnauthorizedError

            user.update(set__online=True)
            user.save()

            expires = datetime.timedelta(hours=3)
            access_token = create_access_token(
                identity=str(user.username), expires_delta=expires
            )
            refresh_token = create_refresh_token(
                identity=str(user.id), expires_delta=expires
            )
            refresh_cookie = [("Set-Cookie", "refresh_token={}".format(refresh_token))]

            return (
                {
                    "access_token": access_token,
                    "username": user.username,
                },
                200,
                refresh_cookie,
            )

        except (UnauthorizedError, DoesNotExist):
            return {"message": "Invalid username or password."}, 401

        except Exception as e:
            return {"message": "Something went wrong."}, 500

post() staticmethod

Authenticate a User object against the User model.

Yields:

Type Description

Check the email.

Check the password.

Parameters:

Name Type Description Default
self

Reference the class itself

required
Flags

Errors and returns status code with error message, 200, otherwise.

Returns:

Type Description

{dict}: JSON Flask Response with an access token and a username. sets a refresh-cookie in headers.

Source code in resources/auth.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
@staticmethod
def post(self):
    """Authenticate a User object against the User model.

    Yields:
        Check the email.
        Check the password.

    Args:
        self: Reference the class itself

    Flags:
        Errors and returns status code with error message,
            200, otherwise.
    Returns:
        {dict}: JSON Flask Response
            with an access token and a username.
            sets a refresh-cookie in headers.
    """

    try:
        body = request.get_json()
        user = User.objects.get(email=body.get("email"))
        authorized = user.check_password(body.get("password"))
        if not authorized:
            raise UnauthorizedError

        user.update(set__online=True)
        user.save()

        expires = datetime.timedelta(hours=3)
        access_token = create_access_token(
            identity=str(user.username), expires_delta=expires
        )
        refresh_token = create_refresh_token(
            identity=str(user.id), expires_delta=expires
        )
        refresh_cookie = [("Set-Cookie", "refresh_token={}".format(refresh_token))]

        return (
            {
                "access_token": access_token,
                "username": user.username,
            },
            200,
            refresh_cookie,
        )

    except (UnauthorizedError, DoesNotExist):
        return {"message": "Invalid username or password."}, 401

    except Exception as e:
        return {"message": "Something went wrong."}, 500

LogoutApi

Bases: Resource

Requests against the Snippet model to api/auth/logout

Source code in resources/auth.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
class LogoutApi(Resource):
    """Requests against the Snippet model to `api/auth/logout`"""

    @jwt_required()
    def post(self):
        """Create a new TokenBlockList document following a User's logout request.

        Yields:
            Save an exiting User's access token to the TokenBlockList database.
            This prevents the access token from being used between the logout event
            and its expiration.
        Flags:
            Errors and returns status code with error message,
                200, otherwise.
        Returns:
            {dict}: JSON Flask Response
                confirmation that the token has been revoked.

        """
        revoked_token = get_jwt()

        jti = revoked_token["jti"]
        owner = revoked_token["sub"]
        created_ts = int(revoked_token["iat"])
        expires_ts = int(revoked_token["exp"])

        created = datetime.datetime.utcfromtimestamp(created_ts).strftime(
            "%Y-%m-%d %H:%M:%S"
        )
        expires = datetime.datetime.utcfromtimestamp(expires_ts).strftime(
            "%Y-%m-%d %H:%M:%S"
        )

        user = User.objects.get(username=owner)
        now = datetime.datetime.now(datetime.timezone.utc)

        block_token = TokenBlocklist(
            jti=jti,
            created_on=created,
            expires_on=expires,
            revoked_on=now,
            revoked_by=user,
        )
        block_token.save()

        user.update(set__online=False)

        return {"message": "JWT revoked"}

post()

Create a new TokenBlockList document following a User's logout request.

Yields:

Type Description

Save an exiting User's access token to the TokenBlockList database.

This prevents the access token from being used between the logout event

and its expiration.

Flags

Errors and returns status code with error message, 200, otherwise.

Returns:

Type Description

{dict}: JSON Flask Response confirmation that the token has been revoked.

Source code in resources/auth.py
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@jwt_required()
def post(self):
    """Create a new TokenBlockList document following a User's logout request.

    Yields:
        Save an exiting User's access token to the TokenBlockList database.
        This prevents the access token from being used between the logout event
        and its expiration.
    Flags:
        Errors and returns status code with error message,
            200, otherwise.
    Returns:
        {dict}: JSON Flask Response
            confirmation that the token has been revoked.

    """
    revoked_token = get_jwt()

    jti = revoked_token["jti"]
    owner = revoked_token["sub"]
    created_ts = int(revoked_token["iat"])
    expires_ts = int(revoked_token["exp"])

    created = datetime.datetime.utcfromtimestamp(created_ts).strftime(
        "%Y-%m-%d %H:%M:%S"
    )
    expires = datetime.datetime.utcfromtimestamp(expires_ts).strftime(
        "%Y-%m-%d %H:%M:%S"
    )

    user = User.objects.get(username=owner)
    now = datetime.datetime.now(datetime.timezone.utc)

    block_token = TokenBlocklist(
        jti=jti,
        created_on=created,
        expires_on=expires,
        revoked_on=now,
        revoked_by=user,
    )
    block_token.save()

    user.update(set__online=False)

    return {"message": "JWT revoked"}

SignupApi

Bases: Resource

Requests against the Snippet model to api/auth/signup

Source code in resources/auth.py
 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
class SignupApi(Resource):
    """Requests against the Snippet model to `api/auth/signup`"""

    def post(self):
        """
        The post function creates a new User object following the User model.
        Yields:
            Save a new User with the required username, email, password fields.
            Hash the password.
            Create three Snippets for the user to have some UI to play with
            upon authentication.
        Flags:
            Errors and returns status code with error message, 200 otherwise.
            Returns: {dict}: JSON Flask Response with an access token and a username sets a refresh cookie in headers.

        Args:
            self: Reference the class in the method definition

        Returns:
            A tuple, the first item is a dictionary with an access token and username

        Note:
            The computation to update, save, reload a Snippet is required to
            ensure Objects have fully landed before they are referenced. It is extra
            complicated for this endpoint as we are awaiting reloads for three models:
            User, Collection and Snippet, all of which vary in `having to exist` before
            the other.
        """

        try:
            body = request.get_json()
            user = User(**body)

            user.hash_password()
            user.save()
            user.reload()

            now = datetime.datetime.now(datetime.timezone.utc)

            id = user.id
            username = user.username

            # Required to instantiate a new reference to the very same
            # and very new User for the purposes of attaching an owner
            # to the snippets.
            saved_user = User.objects.get(username=username)

            snippet_py = Snippet(
                title="{}.py".format(username),
                tags=["first post"],
                description="From Cheat-Hub",
                language="python",
                value="print('hello {}')".format(username),
                addedBy=saved_user,
                addedOn=now,
            )

            snippet_js = Snippet(
                title="{}.js".format(username),
                tags=["first post"],
                description="From Cheat-Hub",
                language="javascript",
                value="console.log('hello {}');".format(username),
                addedBy=saved_user,
                addedOn=now,
            )

            snippet_sh = Snippet(
                title="{}.sh".format(username),
                tags=["first post"],
                description="From Cheat-Hub",
                language="bash",
                value="#!/bin/bash\n\necho 'hello {}'".format(username),
                addedBy=saved_user,
                addedOn=now,
            )

            snippet_py.save()
            snippet_py.reload()
            snippet_js.save()
            snippet_js.reload()
            snippet_sh.save()
            snippet_sh.reload()

            user.update(push_all__snippets_created=[snippet_py, snippet_js, snippet_sh])
            user.save()
            user.reload()

            collection = Collection(
                name="Greetings {}".format(username),
                snippets=[snippet_py, snippet_js, snippet_sh],
                date=now,
                owner=user,
            )

            collection.save()

            user.update(push__collections=collection)
            user.save()

            expires = datetime.timedelta(hours=3)
            access_token = create_access_token(
                identity=str(username), expires_delta=expires
            )
            refresh_token = create_refresh_token(
                identity=str(id), expires_delta=expires
            )
            refresh_cookie = [("Set-Cookie", "refresh_token={}".format(refresh_token))]

            return (
                {
                    "access_token": access_token,
                    "username": username,
                },
                200,
                refresh_cookie,
            )

        except FieldDoesNotExist:
            return {"message": "Request is missing required fields."}, 400

        except NotUniqueError:
            return {"message": "User with given email address already exists."}, 401

        except Exception as e:
            return {"message": "Something went wrong."}, 500

post()

The post function creates a new User object following the User model.

Yields:

Type Description

Save a new User with the required username, email, password fields.

Hash the password.

Create three Snippets for the user to have some UI to play with

upon authentication.

Flags

Errors and returns status code with error message, 200 otherwise. Returns: {dict}: JSON Flask Response with an access token and a username sets a refresh cookie in headers.

Parameters:

Name Type Description Default
self

Reference the class in the method definition

required

Returns:

Type Description

A tuple, the first item is a dictionary with an access token and username

Note

The computation to update, save, reload a Snippet is required to ensure Objects have fully landed before they are referenced. It is extra complicated for this endpoint as we are awaiting reloads for three models: User, Collection and Snippet, all of which vary in having to exist before the other.

Source code in resources/auth.py
 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
def post(self):
    """
    The post function creates a new User object following the User model.
    Yields:
        Save a new User with the required username, email, password fields.
        Hash the password.
        Create three Snippets for the user to have some UI to play with
        upon authentication.
    Flags:
        Errors and returns status code with error message, 200 otherwise.
        Returns: {dict}: JSON Flask Response with an access token and a username sets a refresh cookie in headers.

    Args:
        self: Reference the class in the method definition

    Returns:
        A tuple, the first item is a dictionary with an access token and username

    Note:
        The computation to update, save, reload a Snippet is required to
        ensure Objects have fully landed before they are referenced. It is extra
        complicated for this endpoint as we are awaiting reloads for three models:
        User, Collection and Snippet, all of which vary in `having to exist` before
        the other.
    """

    try:
        body = request.get_json()
        user = User(**body)

        user.hash_password()
        user.save()
        user.reload()

        now = datetime.datetime.now(datetime.timezone.utc)

        id = user.id
        username = user.username

        # Required to instantiate a new reference to the very same
        # and very new User for the purposes of attaching an owner
        # to the snippets.
        saved_user = User.objects.get(username=username)

        snippet_py = Snippet(
            title="{}.py".format(username),
            tags=["first post"],
            description="From Cheat-Hub",
            language="python",
            value="print('hello {}')".format(username),
            addedBy=saved_user,
            addedOn=now,
        )

        snippet_js = Snippet(
            title="{}.js".format(username),
            tags=["first post"],
            description="From Cheat-Hub",
            language="javascript",
            value="console.log('hello {}');".format(username),
            addedBy=saved_user,
            addedOn=now,
        )

        snippet_sh = Snippet(
            title="{}.sh".format(username),
            tags=["first post"],
            description="From Cheat-Hub",
            language="bash",
            value="#!/bin/bash\n\necho 'hello {}'".format(username),
            addedBy=saved_user,
            addedOn=now,
        )

        snippet_py.save()
        snippet_py.reload()
        snippet_js.save()
        snippet_js.reload()
        snippet_sh.save()
        snippet_sh.reload()

        user.update(push_all__snippets_created=[snippet_py, snippet_js, snippet_sh])
        user.save()
        user.reload()

        collection = Collection(
            name="Greetings {}".format(username),
            snippets=[snippet_py, snippet_js, snippet_sh],
            date=now,
            owner=user,
        )

        collection.save()

        user.update(push__collections=collection)
        user.save()

        expires = datetime.timedelta(hours=3)
        access_token = create_access_token(
            identity=str(username), expires_delta=expires
        )
        refresh_token = create_refresh_token(
            identity=str(id), expires_delta=expires
        )
        refresh_cookie = [("Set-Cookie", "refresh_token={}".format(refresh_token))]

        return (
            {
                "access_token": access_token,
                "username": username,
            },
            200,
            refresh_cookie,
        )

    except FieldDoesNotExist:
        return {"message": "Request is missing required fields."}, 400

    except NotUniqueError:
        return {"message": "User with given email address already exists."}, 401

    except Exception as e:
        return {"message": "Something went wrong."}, 500

BadTokenError

Bases: Exception

It creates a new class called BadTokenError that inherits from the Exception class.

Source code in resources/errors.py
81
82
83
84
class BadTokenError(Exception):
    """It creates a new class called BadTokenError that inherits from the Exception class."""

    pass

EmailAlreadyExistsError

Bases: Exception

This class is used to raise an error when a user tries to register with an email that already exists in the database

Source code in resources/errors.py
63
64
65
66
class EmailAlreadyExistsError(Exception):
    """This class is used to raise an error when a user tries to register with an email that already exists in the database"""

    pass

EmailDoesNotExistError

Bases: Exception

This class is used to raise an error when the email address provided does not exist in the database.

Source code in resources/errors.py
75
76
77
78
class EmailDoesNotExistError(Exception):
    """This class is used to raise an error when the email address provided does not exist in the database."""

    pass

ExpiredTokenError

Bases: Exception

This class is used to raise an exception when a token has expired

Source code in resources/errors.py
87
88
89
90
class ExpiredTokenError(Exception):
    """This class is used to raise an exception when a token has expired"""

    pass

InternalServerError

Bases: Exception

It creates a class called InternalServerError that inherits from the Exception class.

Source code in resources/errors.py
16
17
18
19
class InternalServerError(Exception):
    """It creates a class called InternalServerError that inherits from the Exception class."""

    pass

SchemaValidationError

Bases: Exception

It's a custom exception class that will be raised when the schema validation fails

Source code in resources/errors.py
22
23
24
25
class SchemaValidationError(Exception):
    """It's a custom exception class that will be raised when the schema validation fails"""

    pass

SnippetAlreadyExistsError

Bases: Exception

It's a custom exception that is raised when a snippet already exists

Source code in resources/errors.py
28
29
30
31
class SnippetAlreadyExistsError(Exception):
    """ It's a custom exception that is raised when a snippet already exists"""

    pass

SnippetNotExistsError

Bases: Exception

It's a custom exception that is raised when a snippet is not found in the database

Source code in resources/errors.py
45
46
47
48
class SnippetNotExistsError(Exception):
    """It's a custom exception that is raised when a snippet is not found in the database"""

    pass

UnauthorizedError

Bases: Exception

It's a custom exception class that inherits from the built-in Exception class

Source code in resources/errors.py
69
70
71
72
class UnauthorizedError(Exception):
    """It's a custom exception class that inherits from the built-in Exception class"""

    pass

UpdatingSnippetError

Bases: Exception

It's an exception that's raised when a snippet can't be updated

Source code in resources/errors.py
34
35
36
37
class UpdatingSnippetError(Exception):
    """ It's an exception that's raised when a snippet can't be updated"""

    pass

UserNotExistsError

Bases: Exception

This class is used to raise an error when a user does not exist

Source code in resources/errors.py
51
52
53
54
class UserNotExistsError(Exception):
    """This class is used to raise an error when a user does not exist"""

    pass

UsernameAlreadyExistsError

Bases: Exception

This class is used to raise an error when a username already exists in the database

Source code in resources/errors.py
57
58
59
60
class UsernameAlreadyExistsError(Exception):
    """This class is used to raise an error when a username already exists in the database"""

    pass

Status

Bases: Resource

Home endpoint to loosely convey the backend is running /

Source code in resources/status.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Status(Resource):
    """Home endpoint to loosely convey the backend is running `/`"""

    def get(self):
        """
        The get function returns a string that says "Api running"


        Args:
            self: Access variables that belongs to the class

        Returns:
            A dictionary with a key of data and value of "api running"
        """
        try:
            return {"data": "Api running"}
        except:
            return {"data": "An Error Occurred during fetching Api"}

get()

The get function returns a string that says "Api running"

Parameters:

Name Type Description Default
self

Access variables that belongs to the class

required

Returns:

Type Description

A dictionary with a key of data and value of "api running"

Source code in resources/status.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def get(self):
    """
    The get function returns a string that says "Api running"


    Args:
        self: Access variables that belongs to the class

    Returns:
        A dictionary with a key of data and value of "api running"
    """
    try:
        return {"data": "Api running"}
    except:
        return {"data": "An Error Occurred during fetching Api"}

initialize_routes(api)

The initialize_routes function creates the routes for our API. It is called in app.py when you run flask run.

Parameters:

Name Type Description Default
api

Register the resources

required

Returns:

Type Description

The status of the api

Source code in resources/routes.py
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
def initialize_routes(api):
    """
    The initialize_routes function creates the routes for our API.
    It is called in app.py when you run `flask run`.

    Args:
        api: Register the resources

    Returns:
        The status of the api
    """
    """Backend root shows the status of the Api."""
    api.add_resource(Status, "/")

    """Sign up Api: Post. username, email and password. Token returned. """
    api.add_resource(SignupApi, "/api/auth/signup")

    """Sign in Api: Post. username, email and password. Token returned. """
    api.add_resource(LoginApi, "/api/auth/login")

    """Sign out Api: Post. username, email and password. Token returned. """
    api.add_resource(LogoutApi, "/api/auth/logout")

    """Users Api: Get, Post."""
    api.add_resource(UsersApi, "/api/users")

    """User Api: Get, Put, Delete."""
    api.add_resource(UserApi, "/api/users/<id>")

    """Snippets Api: Get, Post."""
    api.add_resource(SnippetsApi, "/api/snippets")
    """Snippets Api: Get, Put, Delete."""
    api.add_resource(SnippetApi, "/api/snippets/<id>")

    """Like/Fave Snippet Api: Post. Token required."""
    api.add_resource(LikeSnippetApi, "/api/likesnippet/<id>")

    """Collections Api: Get, Post."""
    api.add_resource(CollectionsApi, "/api/collections")

    """Collection Api: Get, Put, Delete."""
    api.add_resource(CollectionApi, "/api/collections/<id>")

    """User Profile Snippets Api: username id required"""
    api.add_resource(MySnippetsApi, "/api/users/<id>/snippets")

    """User Profile Fave Snippets Api: username id required"""
    api.add_resource(MyFaveSnippetsApi, "/api/users/<id>/snippets/faves")

    """User Profile Collections Api: username id required"""
    api.add_resource(MyCollectionsApi, "/api/users/<user_id>/collections")

    """User Profile Collection Api: collection id, username id required"""
    api.add_resource(MyCollectionApi, "/api/users/<user_id>/collections/<id>")

    """User Profile Snippet Options Api: username id required"""
    api.add_resource(MySnippetsOptionsApi, "/api/users/<user_id>/snippets/options")

    """User Profile Collections Options Api: username id required"""
    api.add_resource(
        MyCollectionsOptionsApi, "/api/users/<user_id>/collections/options"
    )

    """Search Snippets Api: search text, tag and language arg parsers enabled."""
    api.add_resource(SearchApi, "/api/search")

    """Tag list endpoint: List of all current tags returned. """
    api.add_resource(TagsApi, "/api/tags")

    api.add_resource(ForgotPassword, "/api/auth/forgot")
    api.add_resource(ResetPassword, "/api/auth/reset")

LikeSnippetApi

Bases: Resource

Requests against the Snippet model to api/likesnippet/<id>

Source code in resources/snippet.py
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
class LikeSnippetApi(Resource):
    """Requests against the Snippet model to `api/likesnippet/<id>`"""

    @jwt_required()
    def post(self, id):
        """Add/Remove a Snippet reference to the `snippets_liked` list field of a User
            document with matching id; vice-versa to the `liked_by` list field of matching
            Snippet document.

        Yields:
            Identify a user object against a User model via token.
            Identify a Snippet document based on the `id` param.
            If the User is already in the Snippet's `liked_by` array,
                it means we're `unfaving` it.
            Otherwise, we're `faving` it.
            Update and reload both references to each other.
        Returns: {dict}
            JSON Flask Response, 200 with message
        Note:
            This response is a computation as there is no `Fave` collection.
        """
        user_id = get_jwt_identity()
        user = User.objects.get(username=user_id)
        snippet = Snippet.objects.get(id=id)
        if user in snippet.likedBy:
            print("existing")
            snippet.update(pull__likedBy=user, dec__score=1)
            snippet.save()
            snippet.reload()
            user.update(pull__snippets_liked=snippet)
            user.save()
            user.reload()
            print("snippet unfaved")
            return {"message": "Snippet unfaved"}, 200
        else:
            print("new")
            snippet.update(push__likedBy=user, inc__score=1)
            snippet.save()
            snippet.reload()
            user.update(push__snippets_liked=snippet)
            user.save()
            user.reload()
            print("snippet faved")
            return {"message": "Snippet faved"}, 200

post(id)

Add/Remove a Snippet reference to the snippets_liked list field of a User document with matching id; vice-versa to the liked_by list field of matching Snippet document.

Yields:

Type Description

Identify a user object against a User model via token.

Identify a Snippet document based on the id param.

If the User is already in the Snippet's liked_by array, it means we're unfaving it.

Otherwise, we're faving it.

Update and reload both references to each other.

{dict}

Type Description

JSON Flask Response, 200 with message

Note

This response is a computation as there is no Fave collection.

Source code in resources/snippet.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
@jwt_required()
def post(self, id):
    """Add/Remove a Snippet reference to the `snippets_liked` list field of a User
        document with matching id; vice-versa to the `liked_by` list field of matching
        Snippet document.

    Yields:
        Identify a user object against a User model via token.
        Identify a Snippet document based on the `id` param.
        If the User is already in the Snippet's `liked_by` array,
            it means we're `unfaving` it.
        Otherwise, we're `faving` it.
        Update and reload both references to each other.
    Returns: {dict}
        JSON Flask Response, 200 with message
    Note:
        This response is a computation as there is no `Fave` collection.
    """
    user_id = get_jwt_identity()
    user = User.objects.get(username=user_id)
    snippet = Snippet.objects.get(id=id)
    if user in snippet.likedBy:
        print("existing")
        snippet.update(pull__likedBy=user, dec__score=1)
        snippet.save()
        snippet.reload()
        user.update(pull__snippets_liked=snippet)
        user.save()
        user.reload()
        print("snippet unfaved")
        return {"message": "Snippet unfaved"}, 200
    else:
        print("new")
        snippet.update(push__likedBy=user, inc__score=1)
        snippet.save()
        snippet.reload()
        user.update(push__snippets_liked=snippet)
        user.save()
        user.reload()
        print("snippet faved")
        return {"message": "Snippet faved"}, 200

SnippetApi

Bases: Resource

Requests against the Snippet model to api/snippets/<id> (singular)

Source code in resources/snippet.py
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
class SnippetApi(Resource):
    """Requests against the Snippet model to `api/snippets/<id>` (singular)"""

    def get(self, id):
        """Retrieve one Snippet object with a matching id.

        Yields:
            Identify a Snippet object against a Snippet model
        Flags:
            If it doesn't exist.
        Returns: [{dict}]
            mappable JSON Flask Response, 200
            an array, even with one value to keep the frontend handlers consistent.
                else: Notifies the frontend with status message.
        """
        try:
            snippet = Snippet.objects(id=id)
            response = [
                {
                    "_id": str(ObjectId(doc["id"])),
                    "title": doc["title"],
                    "filename": doc["filename"],
                    "description": doc["description"],
                    "language": doc["language"],
                    "value": doc["value"],
                    "addedBy": doc["addedBy"]["username"],
                    "likedBy": [elem["username"] for elem in doc["likedBy"]],
                    "tags": doc["tags"],
                    "addedOn": doc["addedOn"],
                    "updatedOn": doc["updatedOn"],
                    "private": doc["private"],
                    "source": doc["source"],
                    "score": doc["score"],
                }
                for doc in snippet
            ]

            return jsonify(response)
        except DoesNotExist:

            return {"message": "Code Snippet with given id doesn't exist."}, 410
        except Exception:

            return {"message": "Something went wrong."}, 500

    @jwt_required()
    def put(self, id):
        """Update one Snippet object with a matching id.

        Yields:
            Identify a user object against a User model via token.
            Identify a Snippet document created by the user object.
            Accept all updates to the Snippet document.
        Flags:
            If it doesn't exist.
            If required fields are missing.
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status code and message.
        """
        try:
            user_id = get_jwt_identity()
            username = User.objects.get(username=user_id)
            snippet = Snippet.objects.get(id=id, addedBy=username)
            body = request.get_json()
            now = datetime.datetime.now(datetime.timezone.utc)
            snippet.update(**body, updatedOn=now)
            return {"message": "Snippet updated"}, 200

        except InvalidQueryError:
            return {"message": "Request is missing required fields."}, 400
        except DoesNotExist:
            return {
                "message": "Updating Code Snippet added by someone else is forbidden."
            }, 403

        except Exception:
            return {"message": "Something went wrong."}, 500

    @jwt_required()
    def delete(self, id):
        """Delete one Snippet object with a matching id.

        Yields:
            Identify a user object against a User model via token.
            Identify a Snippet document created by the user object.
            Delete the Snippet document.
        Flags:
            If it doesn't exist and we've gotten this far,
                It means it's made by someone else.
            If required fields are missing.
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status code and message.
        """
        try:
            user_id = get_jwt_identity()
            username = User.objects.get(username=user_id)
            snippet = Snippet.objects.get(id=id, addedBy=username)
            snippet.delete()
            return {"message": "Snippet deleted"}, 200
        except DoesNotExist:
            return {
                "message": "Deleting Code Snippet added by someone else is forbidden."
            }, 403

        except Exception:
            return {"message": "Something went wrong."}, 500

delete(id)

Delete one Snippet object with a matching id.

Yields:

Type Description

Identify a user object against a User model via token.

Identify a Snippet document created by the user object.

Delete the Snippet document.

Flags

If it doesn't exist and we've gotten this far, It means it's made by someone else. If required fields are missing.

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status code and message.

Source code in resources/snippet.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
@jwt_required()
def delete(self, id):
    """Delete one Snippet object with a matching id.

    Yields:
        Identify a user object against a User model via token.
        Identify a Snippet document created by the user object.
        Delete the Snippet document.
    Flags:
        If it doesn't exist and we've gotten this far,
            It means it's made by someone else.
        If required fields are missing.
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status code and message.
    """
    try:
        user_id = get_jwt_identity()
        username = User.objects.get(username=user_id)
        snippet = Snippet.objects.get(id=id, addedBy=username)
        snippet.delete()
        return {"message": "Snippet deleted"}, 200
    except DoesNotExist:
        return {
            "message": "Deleting Code Snippet added by someone else is forbidden."
        }, 403

    except Exception:
        return {"message": "Something went wrong."}, 500

get(id)

Retrieve one Snippet object with a matching id.

Yields:

Type Description

Identify a Snippet object against a Snippet model

Flags

If it doesn't exist.

[{dict}]

Type Description

mappable JSON Flask Response, 200

an array, even with one value to keep the frontend handlers consistent. else: Notifies the frontend with status message.

Source code in resources/snippet.py
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
def get(self, id):
    """Retrieve one Snippet object with a matching id.

    Yields:
        Identify a Snippet object against a Snippet model
    Flags:
        If it doesn't exist.
    Returns: [{dict}]
        mappable JSON Flask Response, 200
        an array, even with one value to keep the frontend handlers consistent.
            else: Notifies the frontend with status message.
    """
    try:
        snippet = Snippet.objects(id=id)
        response = [
            {
                "_id": str(ObjectId(doc["id"])),
                "title": doc["title"],
                "filename": doc["filename"],
                "description": doc["description"],
                "language": doc["language"],
                "value": doc["value"],
                "addedBy": doc["addedBy"]["username"],
                "likedBy": [elem["username"] for elem in doc["likedBy"]],
                "tags": doc["tags"],
                "addedOn": doc["addedOn"],
                "updatedOn": doc["updatedOn"],
                "private": doc["private"],
                "source": doc["source"],
                "score": doc["score"],
            }
            for doc in snippet
        ]

        return jsonify(response)
    except DoesNotExist:

        return {"message": "Code Snippet with given id doesn't exist."}, 410
    except Exception:

        return {"message": "Something went wrong."}, 500

put(id)

Update one Snippet object with a matching id.

Yields:

Type Description

Identify a user object against a User model via token.

Identify a Snippet document created by the user object.

Accept all updates to the Snippet document.

Flags

If it doesn't exist. If required fields are missing.

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status code and message.

Source code in resources/snippet.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@jwt_required()
def put(self, id):
    """Update one Snippet object with a matching id.

    Yields:
        Identify a user object against a User model via token.
        Identify a Snippet document created by the user object.
        Accept all updates to the Snippet document.
    Flags:
        If it doesn't exist.
        If required fields are missing.
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status code and message.
    """
    try:
        user_id = get_jwt_identity()
        username = User.objects.get(username=user_id)
        snippet = Snippet.objects.get(id=id, addedBy=username)
        body = request.get_json()
        now = datetime.datetime.now(datetime.timezone.utc)
        snippet.update(**body, updatedOn=now)
        return {"message": "Snippet updated"}, 200

    except InvalidQueryError:
        return {"message": "Request is missing required fields."}, 400
    except DoesNotExist:
        return {
            "message": "Updating Code Snippet added by someone else is forbidden."
        }, 403

    except Exception:
        return {"message": "Something went wrong."}, 500

SnippetsApi

Bases: Resource

Requests against the Snippet model to api/snippets (plural)

Source code in resources/snippet.py
 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
class SnippetsApi(Resource):
    """Requests against the Snippet model to `api/snippets` (plural)"""

    def get(self):
        """Retrieve a list of public snippets.

        Yields:
            Parse web args from the request.
            Get all existing tags from the databse.
            Query snippets that include tags from the request.
            If the tag field is empty,
                return all snippets with all tags.

        Returns:
            [{dict}]: JSON Flask Response
            A paginated list of Snippet objects
        """

        tag_request = tag_parser.parse_args()
        tags = tag_request["tags"]

        page_request = pagination_parser.parse_args()
        page = page_request["page"]
        per_page = page_request["per_page"]

        all_tags_arr = all_tags()

        paginated = (
            Snippet.objects(
                tags__in=tags if tags else all_tags_arr,
            )
            .order_by("-addedOn")
            .paginate(
                page=page,
                per_page=per_page,
            )
        )

        meta = pagination_meta(paginated)
        links = pagination_links(paginated, "snippetsapi")

        resp = {
            "links": links,
            "has_prev": paginated.has_prev,
            "has_next": paginated.has_next,
            "page": paginated.page,
            "total_pages": paginated.pages,
            "items_per_page": paginated.per_page,
            "total_items": paginated.total,
            "items": [
                {
                    "_id": str(ObjectId(k["id"])),
                    "title": k["title"],
                    "filename": k["filename"],
                    "description": k["description"],
                    "language": k["language"],
                    "value": k["value"],
                    "addedBy": k["addedBy"]["username"],
                    "likedBy": [elem["username"] for elem in k["likedBy"]],
                    "tags": k["tags"],
                    "addedOn": k["addedOn"],
                    "updatedOn": k["updatedOn"],
                    "private": k["private"],
                    "source": k["source"],
                    "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
                }
                for k in paginated.items
            ],
        }
        return jsonify(resp)

    @jwt_required()
    def post(self):
        """Save a Snippet document created by an authorized User.

        Yields:
            Identify a user object against a User model
            Set a Snippet document based on the Snippet model.
            Add the Snippet to the User's `snippets_created` field.
        Flags:
            File and validation errors
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status message.
        """
        try:
            user_id = get_jwt_identity()
            body = request.get_json()
            user = User.objects.get(username=user_id)
            now = datetime.datetime.now(datetime.timezone.utc)

            snippet = Snippet(**body, addedBy=user, addedOn=now)
            snippet.save()
            user.update(push__snippets_created=snippet)
            user.save()
            id = snippet.id
            return {"id": str(id)}, 200

        except (FieldDoesNotExist, ValidationError):
            return {"message": "Request is missing required fields."}, 400
        except NotUniqueError:
            return {"message": "Code Snippet with given name already exists."}, 409
        except Exception as e:
            return {"message": "Something went wrong."}, 500

get()

Retrieve a list of public snippets.

Yields:

Type Description

Parse web args from the request.

Get all existing tags from the databse.

Query snippets that include tags from the request.

If the tag field is empty, return all snippets with all tags.

Returns:

Type Description

[{dict}]: JSON Flask Response

A paginated list of Snippet objects

Source code in resources/snippet.py
 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
def get(self):
    """Retrieve a list of public snippets.

    Yields:
        Parse web args from the request.
        Get all existing tags from the databse.
        Query snippets that include tags from the request.
        If the tag field is empty,
            return all snippets with all tags.

    Returns:
        [{dict}]: JSON Flask Response
        A paginated list of Snippet objects
    """

    tag_request = tag_parser.parse_args()
    tags = tag_request["tags"]

    page_request = pagination_parser.parse_args()
    page = page_request["page"]
    per_page = page_request["per_page"]

    all_tags_arr = all_tags()

    paginated = (
        Snippet.objects(
            tags__in=tags if tags else all_tags_arr,
        )
        .order_by("-addedOn")
        .paginate(
            page=page,
            per_page=per_page,
        )
    )

    meta = pagination_meta(paginated)
    links = pagination_links(paginated, "snippetsapi")

    resp = {
        "links": links,
        "has_prev": paginated.has_prev,
        "has_next": paginated.has_next,
        "page": paginated.page,
        "total_pages": paginated.pages,
        "items_per_page": paginated.per_page,
        "total_items": paginated.total,
        "items": [
            {
                "_id": str(ObjectId(k["id"])),
                "title": k["title"],
                "filename": k["filename"],
                "description": k["description"],
                "language": k["language"],
                "value": k["value"],
                "addedBy": k["addedBy"]["username"],
                "likedBy": [elem["username"] for elem in k["likedBy"]],
                "tags": k["tags"],
                "addedOn": k["addedOn"],
                "updatedOn": k["updatedOn"],
                "private": k["private"],
                "source": k["source"],
                "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
            }
            for k in paginated.items
        ],
    }
    return jsonify(resp)

post()

Save a Snippet document created by an authorized User.

Yields:

Type Description

Identify a user object against a User model

Set a Snippet document based on the Snippet model.

Add the Snippet to the User's snippets_created field.

Flags

File and validation errors

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status message.

Source code in resources/snippet.py
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
@jwt_required()
def post(self):
    """Save a Snippet document created by an authorized User.

    Yields:
        Identify a user object against a User model
        Set a Snippet document based on the Snippet model.
        Add the Snippet to the User's `snippets_created` field.
    Flags:
        File and validation errors
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status message.
    """
    try:
        user_id = get_jwt_identity()
        body = request.get_json()
        user = User.objects.get(username=user_id)
        now = datetime.datetime.now(datetime.timezone.utc)

        snippet = Snippet(**body, addedBy=user, addedOn=now)
        snippet.save()
        user.update(push__snippets_created=snippet)
        user.save()
        id = snippet.id
        return {"id": str(id)}, 200

    except (FieldDoesNotExist, ValidationError):
        return {"message": "Request is missing required fields."}, 400
    except NotUniqueError:
        return {"message": "Code Snippet with given name already exists."}, 409
    except Exception as e:
        return {"message": "Something went wrong."}, 500

CollectionApi

Bases: Resource

Requests against the Collection model to api/collections/<id> (singular)

Source code in resources/collection.py
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
class CollectionApi(Resource):
    """Requests against the Collection model to `api/collections/<id>` (singular)"""

    def get(self, id):
        """Retrieve one Collection object with a matching id.

        Yields:
            Identify a Collection object against a Collection model
        Flags:
            If it doesn't exist.
        Returns: [{dict}]
            mappable JSON Flask Response, 200,
            with dereferenced nested fields full of data,
            as an array even for one document to keep the frontend handlers consistent.
                else: Notifies the frontend with status message.
        """
        try:
            collection = []
            for doc in Collection.objects(id=id):
                collection.append(
                    {
                        "_id": str(ObjectId(doc["id"])),
                        "name": doc["name"],
                        "owner": doc["owner"]["username"],
                        "private": doc["private"],
                        "snippets_id": [
                            {"label": i["title"], "value": str(ObjectId(i["id"]))}
                            for i in doc["snippets"]
                        ],
                        "snippets": [
                            {
                                "_id": str(ObjectId(k["id"])),
                                "title": k["title"],
                                "filename": k["filename"],
                                "description": k["description"],
                                "language": k["language"],
                                "value": k["value"],
                                "addedBy": k["addedBy"]["username"],
                                "likedBy": [elem["username"] for elem in k["likedBy"]],
                                "tags": k["tags"],
                                "addedOn": k["addedOn"],
                                "updatedOn": k["updatedOn"],
                                "private": k["private"],
                                "source": k["source"],
                            }
                            for k in doc["snippets"]
                        ],
                    }
                )

            return jsonify(collection)

        except DoesNotExist:
            return {"message": "Collection with given id doesn't exist."}, 410
        except Exception:
            return {"message": "Something went wrong."}, 500

    @jwt_required()
    def put(self, id):
        """Update one Collection object with a matching id.

        Yields:
            Identify a user object against a User model via token.
            Identify a Collection document created by the user object.
            Iterate through the `snippets` field of the request.
                Identify a Snippet object against the Snippet model
                for every item in the `snippets` field.
            Set this array as a the new `snippets` field in the Collection.

        Flags:
            If it doesn't exist.
            If required fields are missing.
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status code and message.
        Note:
            Looping and setting a new array seems like an expensive computation
            every time someone updates a collection, and the snippets within it.
            Why can't we just keep it if it's already there, add it if it isn't?
            Because the Snippet has to first exist in the database in order to
            `find` and add it to a Collection, the result will always be an
            `all or not all` flip. An alternative might be to create separate endpoints
            for adding and removing values from a nested document, which may or may
            not require the same amount of computation.
        """
        try:
            user_id = get_jwt_identity()
            user = User.objects.get(username=user_id)
            collection = Collection.objects.get(id=id, owner=user)
            body = request.get_json()
            name = body["name"]
            snippets = body["snippets"]
            now = datetime.datetime.now(datetime.timezone.utc)

            snippet_array = []
            for snippet in snippets:
                snip = Snippet.objects.get(id=snippet)
                snippet_array.append(snip)

            collection.update(name=name, date=now, set__snippets=snippet_array)
            collection.save()

            return {"message": "Collection updated"}, 200

        except InvalidQueryError:
            return {"message": "Request is missing required fields."}, 400
        except DoesNotExist:
            return {
                "message": "Updating Collection added by someone else is forbidden."
            }, 403
        except Exception:
            return {"message": "Something went wrong."}, 500

    @jwt_required()
    def delete(self, id):
        """Delete one Collection object with a matching id.

        Yields:
            Identify a user object against a User model via token.
            Identify a Collection document created by the user object.
            Delete the Collection document.
        Flags:
            If it doesn't exist and we've gotten this far,
                It means it's made by someone else.
            If required fields are missing.
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status code and message.
        """
        try:
            user_id = get_jwt_identity()
            user = User.objects.get(username=user_id)
            collection = Collection.objects.get(id=id, owner=user)
            collection.delete()
            return {"message": "Collection deleted"}, 200
        except DoesNotExist:
            return {
                "message": "Deleting Collection added by someone else is forbidden."
            }, 403
        except Exception:
            return {"message": "Something went wrong."}, 500

delete(id)

Delete one Collection object with a matching id.

Yields:

Type Description

Identify a user object against a User model via token.

Identify a Collection document created by the user object.

Delete the Collection document.

Flags

If it doesn't exist and we've gotten this far, It means it's made by someone else. If required fields are missing.

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status code and message.

Source code in resources/collection.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
@jwt_required()
def delete(self, id):
    """Delete one Collection object with a matching id.

    Yields:
        Identify a user object against a User model via token.
        Identify a Collection document created by the user object.
        Delete the Collection document.
    Flags:
        If it doesn't exist and we've gotten this far,
            It means it's made by someone else.
        If required fields are missing.
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status code and message.
    """
    try:
        user_id = get_jwt_identity()
        user = User.objects.get(username=user_id)
        collection = Collection.objects.get(id=id, owner=user)
        collection.delete()
        return {"message": "Collection deleted"}, 200
    except DoesNotExist:
        return {
            "message": "Deleting Collection added by someone else is forbidden."
        }, 403
    except Exception:
        return {"message": "Something went wrong."}, 500

get(id)

Retrieve one Collection object with a matching id.

Yields:

Type Description

Identify a Collection object against a Collection model

Flags

If it doesn't exist.

[{dict}]

Type Description

mappable JSON Flask Response, 200,

with dereferenced nested fields full of data,

as an array even for one document to keep the frontend handlers consistent. else: Notifies the frontend with status message.

Source code in resources/collection.py
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
def get(self, id):
    """Retrieve one Collection object with a matching id.

    Yields:
        Identify a Collection object against a Collection model
    Flags:
        If it doesn't exist.
    Returns: [{dict}]
        mappable JSON Flask Response, 200,
        with dereferenced nested fields full of data,
        as an array even for one document to keep the frontend handlers consistent.
            else: Notifies the frontend with status message.
    """
    try:
        collection = []
        for doc in Collection.objects(id=id):
            collection.append(
                {
                    "_id": str(ObjectId(doc["id"])),
                    "name": doc["name"],
                    "owner": doc["owner"]["username"],
                    "private": doc["private"],
                    "snippets_id": [
                        {"label": i["title"], "value": str(ObjectId(i["id"]))}
                        for i in doc["snippets"]
                    ],
                    "snippets": [
                        {
                            "_id": str(ObjectId(k["id"])),
                            "title": k["title"],
                            "filename": k["filename"],
                            "description": k["description"],
                            "language": k["language"],
                            "value": k["value"],
                            "addedBy": k["addedBy"]["username"],
                            "likedBy": [elem["username"] for elem in k["likedBy"]],
                            "tags": k["tags"],
                            "addedOn": k["addedOn"],
                            "updatedOn": k["updatedOn"],
                            "private": k["private"],
                            "source": k["source"],
                        }
                        for k in doc["snippets"]
                    ],
                }
            )

        return jsonify(collection)

    except DoesNotExist:
        return {"message": "Collection with given id doesn't exist."}, 410
    except Exception:
        return {"message": "Something went wrong."}, 500

put(id)

Update one Collection object with a matching id.

Yields:

Type Description

Identify a user object against a User model via token.

Identify a Collection document created by the user object.

Iterate through the snippets field of the request. Identify a Snippet object against the Snippet model for every item in the snippets field.

Set this array as a the new snippets field in the Collection.

Flags

If it doesn't exist. If required fields are missing.

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status code and message.

Note

Looping and setting a new array seems like an expensive computation every time someone updates a collection, and the snippets within it. Why can't we just keep it if it's already there, add it if it isn't? Because the Snippet has to first exist in the database in order to find and add it to a Collection, the result will always be an all or not all flip. An alternative might be to create separate endpoints for adding and removing values from a nested document, which may or may not require the same amount of computation.

Source code in resources/collection.py
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
@jwt_required()
def put(self, id):
    """Update one Collection object with a matching id.

    Yields:
        Identify a user object against a User model via token.
        Identify a Collection document created by the user object.
        Iterate through the `snippets` field of the request.
            Identify a Snippet object against the Snippet model
            for every item in the `snippets` field.
        Set this array as a the new `snippets` field in the Collection.

    Flags:
        If it doesn't exist.
        If required fields are missing.
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status code and message.
    Note:
        Looping and setting a new array seems like an expensive computation
        every time someone updates a collection, and the snippets within it.
        Why can't we just keep it if it's already there, add it if it isn't?
        Because the Snippet has to first exist in the database in order to
        `find` and add it to a Collection, the result will always be an
        `all or not all` flip. An alternative might be to create separate endpoints
        for adding and removing values from a nested document, which may or may
        not require the same amount of computation.
    """
    try:
        user_id = get_jwt_identity()
        user = User.objects.get(username=user_id)
        collection = Collection.objects.get(id=id, owner=user)
        body = request.get_json()
        name = body["name"]
        snippets = body["snippets"]
        now = datetime.datetime.now(datetime.timezone.utc)

        snippet_array = []
        for snippet in snippets:
            snip = Snippet.objects.get(id=snippet)
            snippet_array.append(snip)

        collection.update(name=name, date=now, set__snippets=snippet_array)
        collection.save()

        return {"message": "Collection updated"}, 200

    except InvalidQueryError:
        return {"message": "Request is missing required fields."}, 400
    except DoesNotExist:
        return {
            "message": "Updating Collection added by someone else is forbidden."
        }, 403
    except Exception:
        return {"message": "Something went wrong."}, 500

CollectionsApi

Bases: Resource

Requests against the Collection model to api/collections (plural)

Source code in resources/collection.py
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
class CollectionsApi(Resource):
    """Requests against the Collection model to `api/collections` (plural)"""

    def get(self):
        """Retrieve loose list of all Collections.

        Yields:
            jsonify a Query object of the Collection model

        Returns:
            [{dict}]: JSON Flask Response
            A loose reference list of Collection objects
        Note:
            This endpoint is not the primary endpoint for fetching field details,
        """
        collections = Collection.objects(private=False)
        response = [
            {
                "_id": str(ObjectId(doc["id"])),
                "name": doc["name"],
                "owner": doc["owner"]["username"],
                "snippets": [
                    {
                        "snippet_title": k["title"],
                        "snippet_id": str(ObjectId(k["id"])),
                    }
                    for k in doc["snippets"]
                ],
                "private": doc["private"],
            }
            for doc in collections
        ]

        return jsonify(response)

    @jwt_required()
    def post(self):
        """Save a Collection document created by an authorized User.

        Yields:
            Identify a user object against a User model
            Set a Collection document based on the Collection model.
            Add the Collection to the User's `collections` field.
        Flags:
            File and validation errors
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status message.
        """
        try:
            user_id = get_jwt_identity()
            body = request.get_json()
            owner = User.objects.get(username=user_id)
            now = datetime.datetime.now(datetime.timezone.utc)

            collection = Collection(**body, owner=owner, date=now)
            collection.save()
            owner.update(push__collections=collection)
            owner.save()
            id = collection.id
            return {"id": str(id)}, 200

        except (FieldDoesNotExist, ValidationError):
            return {"message": "Request is missing required fields."}, 400
        except NotUniqueError:
            return {"message": "Collection with given name already exists."}, 409
        except Exception as e:
            return {"message": "Something went wrong."}, 500

get()

Retrieve loose list of all Collections.

Yields:

Type Description

jsonify a Query object of the Collection model

Returns:

Type Description

[{dict}]: JSON Flask Response

A loose reference list of Collection objects

Note

This endpoint is not the primary endpoint for fetching field details,

Source code in resources/collection.py
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
def get(self):
    """Retrieve loose list of all Collections.

    Yields:
        jsonify a Query object of the Collection model

    Returns:
        [{dict}]: JSON Flask Response
        A loose reference list of Collection objects
    Note:
        This endpoint is not the primary endpoint for fetching field details,
    """
    collections = Collection.objects(private=False)
    response = [
        {
            "_id": str(ObjectId(doc["id"])),
            "name": doc["name"],
            "owner": doc["owner"]["username"],
            "snippets": [
                {
                    "snippet_title": k["title"],
                    "snippet_id": str(ObjectId(k["id"])),
                }
                for k in doc["snippets"]
            ],
            "private": doc["private"],
        }
        for doc in collections
    ]

    return jsonify(response)

post()

Save a Collection document created by an authorized User.

Yields:

Type Description

Identify a user object against a User model

Set a Collection document based on the Collection model.

Add the Collection to the User's collections field.

Flags

File and validation errors

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status message.

Source code in resources/collection.py
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
@jwt_required()
def post(self):
    """Save a Collection document created by an authorized User.

    Yields:
        Identify a user object against a User model
        Set a Collection document based on the Collection model.
        Add the Collection to the User's `collections` field.
    Flags:
        File and validation errors
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status message.
    """
    try:
        user_id = get_jwt_identity()
        body = request.get_json()
        owner = User.objects.get(username=user_id)
        now = datetime.datetime.now(datetime.timezone.utc)

        collection = Collection(**body, owner=owner, date=now)
        collection.save()
        owner.update(push__collections=collection)
        owner.save()
        id = collection.id
        return {"id": str(id)}, 200

    except (FieldDoesNotExist, ValidationError):
        return {"message": "Request is missing required fields."}, 400
    except NotUniqueError:
        return {"message": "Collection with given name already exists."}, 409
    except Exception as e:
        return {"message": "Something went wrong."}, 500

MyCollectionApi

Bases: Resource

Requests against the Snippet model to api/users/<user_id>/collections/<id>

Source code in resources/profile.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
class MyCollectionApi(Resource):
    """Requests against the Snippet model to `api/users/<user_id>/collections/<id>`"""

    def get(self, user_id, id):
        """Retrieve one Collection created by a user.

        Yields:
            Identify a User object against a User model via username (user_id).
            jsonify a Query object to the Collections database of a
            Collection object with field `owner` equal to the User
            model via unique username `user_id`, and a `collecion_id`
            equal to the query `id`.

        Returns:
            [{dict}]: JSON Flask Response
            A healthy Collection object with unnested, dereferenced Snippets
        Note:
            This endpoint returns a response identical to `api/collections/<id>`;
            the only difference being the `user_id` argument.
            This is to accommodate Collections flagged as `private` to the User, a
            field that is currently false for all Collections by default.
        """
        try:
            user = User.objects.get(username=user_id)
            collection = []
            for doc in Collection.objects(owner=user, id=id):
                collection.append(
                    {
                        "_id": str(ObjectId(doc["id"])),
                        "name": doc["name"],
                        "owner": doc["owner"]["username"],
                        "private": doc["private"],
                        "url": url_for(
                            "mycollectionapi",
                            user_id=user_id,
                            id=str(ObjectId(doc["id"])),
                        ),
                        "snippets": [
                            {
                                "_id": str(ObjectId(k["id"])),
                                "title": k["title"],
                                "filename": k["filename"],
                                "description": k["description"],
                                "language": k["language"],
                                "value": k["value"],
                                "addedBy": k["addedBy"]["username"],
                                "likedBy": [elem["username"] for elem in k["likedBy"]],
                                "tags": k["tags"],
                                "addedOn": k["addedOn"],
                                "updatedOn": k["updatedOn"],
                                "private": k["private"],
                                "source": k["source"],
                                "url": url_for(
                                    "snippetapi", id=str(ObjectId(doc["id"]))
                                ),
                            }
                            for k in doc["snippets"]
                        ],
                    }
                )

            return jsonify(collection)

        except DoesNotExist:
            raise SnippetNotExistsError
        except Exception:
            raise InternalServerError

get(user_id, id)

Retrieve one Collection created by a user.

Yields:

Type Description

Identify a User object against a User model via username (user_id).

jsonify a Query object to the Collections database of a

Collection object with field owner equal to the User

model via unique username user_id, and a collecion_id

equal to the query id.

Returns:

Type Description

[{dict}]: JSON Flask Response

A healthy Collection object with unnested, dereferenced Snippets

Note

This endpoint returns a response identical to api/collections/<id>; the only difference being the user_id argument. This is to accommodate Collections flagged as private to the User, a field that is currently false for all Collections by default.

Source code in resources/profile.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def get(self, user_id, id):
    """Retrieve one Collection created by a user.

    Yields:
        Identify a User object against a User model via username (user_id).
        jsonify a Query object to the Collections database of a
        Collection object with field `owner` equal to the User
        model via unique username `user_id`, and a `collecion_id`
        equal to the query `id`.

    Returns:
        [{dict}]: JSON Flask Response
        A healthy Collection object with unnested, dereferenced Snippets
    Note:
        This endpoint returns a response identical to `api/collections/<id>`;
        the only difference being the `user_id` argument.
        This is to accommodate Collections flagged as `private` to the User, a
        field that is currently false for all Collections by default.
    """
    try:
        user = User.objects.get(username=user_id)
        collection = []
        for doc in Collection.objects(owner=user, id=id):
            collection.append(
                {
                    "_id": str(ObjectId(doc["id"])),
                    "name": doc["name"],
                    "owner": doc["owner"]["username"],
                    "private": doc["private"],
                    "url": url_for(
                        "mycollectionapi",
                        user_id=user_id,
                        id=str(ObjectId(doc["id"])),
                    ),
                    "snippets": [
                        {
                            "_id": str(ObjectId(k["id"])),
                            "title": k["title"],
                            "filename": k["filename"],
                            "description": k["description"],
                            "language": k["language"],
                            "value": k["value"],
                            "addedBy": k["addedBy"]["username"],
                            "likedBy": [elem["username"] for elem in k["likedBy"]],
                            "tags": k["tags"],
                            "addedOn": k["addedOn"],
                            "updatedOn": k["updatedOn"],
                            "private": k["private"],
                            "source": k["source"],
                            "url": url_for(
                                "snippetapi", id=str(ObjectId(doc["id"]))
                            ),
                        }
                        for k in doc["snippets"]
                    ],
                }
            )

        return jsonify(collection)

    except DoesNotExist:
        raise SnippetNotExistsError
    except Exception:
        raise InternalServerError

MyCollectionsApi

Bases: Resource

Requests against the Snippet model to api/users/<id>/collections

Source code in resources/profile.py
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
188
189
190
191
192
193
194
class MyCollectionsApi(Resource):
    """Requests against the Snippet model to `api/users/<id>/collections`"""

    def get(self, user_id):
        """Retrieve a complete list of all Collections created by a user.

        Yields:
            Identify a User object against a User model via username (id).
            jsonify a Query object to the Collections database of all
            Collection objects with field `owner` equal to the User
            model via unique username and/or id.

        Returns:
            [{dict}]: JSON Flask Response
            A complete list of Snippet objects, with all nested fields
            dereferenced.
        Note:
            This endpoint is the primary endpoint for fetching User's
            Snippets profile.
        """

        user = User.objects.get(username=user_id)
        collections = Collection.objects(owner=user).order_by("-date")

        response = [
            {
                "_id": str(ObjectId(doc["id"])),
                "name": doc["name"],
                "owner": doc["owner"]["username"],
                "private": doc["private"],
                "url": url_for(
                    "mycollectionapi", user_id=user_id, id=str(ObjectId(doc["id"]))
                ),
                "snippets": [
                    {
                        "_id": str(ObjectId(k["id"])),
                        "title": k["title"],
                        "filename": k["filename"],
                        "description": k["description"],
                        "language": k["language"],
                        "value": k["value"],
                        "addedBy": k["addedBy"]["username"],
                        "likedBy": [elem["username"] for elem in k["likedBy"]],
                        "tags": k["tags"],
                        "addedOn": k["addedOn"],
                        "updatedOn": k["updatedOn"],
                        "private": k["private"],
                        "source": k["source"],
                        "url": url_for("snippetapi", id=str(ObjectId(doc["id"]))),
                    }
                    for k in doc["snippets"]
                ],
            }
            for doc in collections
        ]

        return jsonify(response)

get(user_id)

Retrieve a complete list of all Collections created by a user.

Yields:

Type Description

Identify a User object against a User model via username (id).

jsonify a Query object to the Collections database of all

Collection objects with field owner equal to the User

model via unique username and/or id.

Returns:

Type Description

[{dict}]: JSON Flask Response

A complete list of Snippet objects, with all nested fields

dereferenced.

Note

This endpoint is the primary endpoint for fetching User's Snippets profile.

Source code in resources/profile.py
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
188
189
190
191
192
193
194
def get(self, user_id):
    """Retrieve a complete list of all Collections created by a user.

    Yields:
        Identify a User object against a User model via username (id).
        jsonify a Query object to the Collections database of all
        Collection objects with field `owner` equal to the User
        model via unique username and/or id.

    Returns:
        [{dict}]: JSON Flask Response
        A complete list of Snippet objects, with all nested fields
        dereferenced.
    Note:
        This endpoint is the primary endpoint for fetching User's
        Snippets profile.
    """

    user = User.objects.get(username=user_id)
    collections = Collection.objects(owner=user).order_by("-date")

    response = [
        {
            "_id": str(ObjectId(doc["id"])),
            "name": doc["name"],
            "owner": doc["owner"]["username"],
            "private": doc["private"],
            "url": url_for(
                "mycollectionapi", user_id=user_id, id=str(ObjectId(doc["id"]))
            ),
            "snippets": [
                {
                    "_id": str(ObjectId(k["id"])),
                    "title": k["title"],
                    "filename": k["filename"],
                    "description": k["description"],
                    "language": k["language"],
                    "value": k["value"],
                    "addedBy": k["addedBy"]["username"],
                    "likedBy": [elem["username"] for elem in k["likedBy"]],
                    "tags": k["tags"],
                    "addedOn": k["addedOn"],
                    "updatedOn": k["updatedOn"],
                    "private": k["private"],
                    "source": k["source"],
                    "url": url_for("snippetapi", id=str(ObjectId(doc["id"]))),
                }
                for k in doc["snippets"]
            ],
        }
        for doc in collections
    ]

    return jsonify(response)

MyCollectionsOptionsApi

Bases: Resource

Requests against the Collection model to api/users/<user_id>/collections/options

Source code in resources/profile.py
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
class MyCollectionsOptionsApi(Resource):
    """Requests against the Collection model to `api/users/<user_id>/collections/options`"""

    def get(self, user_id):
        """Retrieve an array of all Collections available to the user.

        Yields:
            Identify a User object against a User model via username (user_id).
            jsonify a Query object to the Collections database of all
            Collection objects with field `owner` equal to the User
            model via unique username `user_id`, formatted as `options` in
            an HTML `select` element.

        Returns:
            [{dict}]: JSON Flask Response
                array of Collections with `label` and `value` keys for `Select` UI.
        Note:
            This key endpoint is what allows the frontend to quickly present documents
            as creatable and/or multi-select options immediately following updates to
            a user's Collections profile.
        """
        user = User.objects.get(username=user_id)
        collections = Collection.objects(owner=user)
        response = [
            {"label": doc["name"], "value": str(ObjectId(doc["id"]))}
            for doc in collections
        ]
        return jsonify(response)

get(user_id)

Retrieve an array of all Collections available to the user.

Yields:

Type Description

Identify a User object against a User model via username (user_id).

jsonify a Query object to the Collections database of all

Collection objects with field owner equal to the User

model via unique username user_id, formatted as options in

an HTML select element.

Returns:

Type Description

[{dict}]: JSON Flask Response array of Collections with label and value keys for Select UI.

Note

This key endpoint is what allows the frontend to quickly present documents as creatable and/or multi-select options immediately following updates to a user's Collections profile.

Source code in resources/profile.py
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def get(self, user_id):
    """Retrieve an array of all Collections available to the user.

    Yields:
        Identify a User object against a User model via username (user_id).
        jsonify a Query object to the Collections database of all
        Collection objects with field `owner` equal to the User
        model via unique username `user_id`, formatted as `options` in
        an HTML `select` element.

    Returns:
        [{dict}]: JSON Flask Response
            array of Collections with `label` and `value` keys for `Select` UI.
    Note:
        This key endpoint is what allows the frontend to quickly present documents
        as creatable and/or multi-select options immediately following updates to
        a user's Collections profile.
    """
    user = User.objects.get(username=user_id)
    collections = Collection.objects(owner=user)
    response = [
        {"label": doc["name"], "value": str(ObjectId(doc["id"]))}
        for doc in collections
    ]
    return jsonify(response)

MyFaveSnippetsApi

Bases: Resource

Requests against the Snippet model to api/users/<id>/snippets/faves

Source code in resources/profile.py
 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
class MyFaveSnippetsApi(Resource):
    """Requests against the Snippet model to `api/users/<id>/snippets/faves`"""

    def get(self, id):
        """Retrieve a complete list of all Snippets `liked` by a user.

        Yields:
            Identify a User object against a User model via username.
            jsonify a Query object to the Snippets database of all
            Snippet objects with a `likedBy` list field that includes the
            User.

        Returns:
            [{dict}]: JSON Flask Response
            A complete list of Snippet objects, with all nested fields
            dereferenced.
        Note:
            This API response is modeled to be received as a Collection object,
            even though it is a pure computation of values in nested document
            fields. This is done to simplofy frontend handlers as the `Faves`
            endpoint's UI is rendered as a unique `collection`.

        """
        user = User.objects.get(username=id)
        snips = Snippet.objects(likedBy=user)
        response = [
            {
                "_id": "faves",
                "name": "Faves",
                "owner": id,
                "private": False,
                "url": url_for("myfavesnippetsapi", id=id),
                "snippets": [
                    {
                        "_id": str(ObjectId(k["id"])),
                        "title": k["title"],
                        "filename": k["filename"],
                        "description": k["description"],
                        "language": k["language"],
                        "value": k["value"],
                        "addedBy": k["addedBy"]["username"],
                        "likedBy": [elem["username"] for elem in k["likedBy"]],
                        "tags": k["tags"],
                        "addedOn": k["addedOn"],
                        "updatedOn": k["updatedOn"],
                        "private": k["private"],
                        "source": k["source"],
                        "url": url_for("myfavesnippetsapi", id=user),
                    }
                    for k in snips
                ],
            }
        ]

        return jsonify(response)

get(id)

Retrieve a complete list of all Snippets liked by a user.

Yields:

Type Description

Identify a User object against a User model via username.

jsonify a Query object to the Snippets database of all

Snippet objects with a likedBy list field that includes the

User.

Returns:

Type Description

[{dict}]: JSON Flask Response

A complete list of Snippet objects, with all nested fields

dereferenced.

Note

This API response is modeled to be received as a Collection object, even though it is a pure computation of values in nested document fields. This is done to simplofy frontend handlers as the Faves endpoint's UI is rendered as a unique collection.

Source code in resources/profile.py
 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
def get(self, id):
    """Retrieve a complete list of all Snippets `liked` by a user.

    Yields:
        Identify a User object against a User model via username.
        jsonify a Query object to the Snippets database of all
        Snippet objects with a `likedBy` list field that includes the
        User.

    Returns:
        [{dict}]: JSON Flask Response
        A complete list of Snippet objects, with all nested fields
        dereferenced.
    Note:
        This API response is modeled to be received as a Collection object,
        even though it is a pure computation of values in nested document
        fields. This is done to simplofy frontend handlers as the `Faves`
        endpoint's UI is rendered as a unique `collection`.

    """
    user = User.objects.get(username=id)
    snips = Snippet.objects(likedBy=user)
    response = [
        {
            "_id": "faves",
            "name": "Faves",
            "owner": id,
            "private": False,
            "url": url_for("myfavesnippetsapi", id=id),
            "snippets": [
                {
                    "_id": str(ObjectId(k["id"])),
                    "title": k["title"],
                    "filename": k["filename"],
                    "description": k["description"],
                    "language": k["language"],
                    "value": k["value"],
                    "addedBy": k["addedBy"]["username"],
                    "likedBy": [elem["username"] for elem in k["likedBy"]],
                    "tags": k["tags"],
                    "addedOn": k["addedOn"],
                    "updatedOn": k["updatedOn"],
                    "private": k["private"],
                    "source": k["source"],
                    "url": url_for("myfavesnippetsapi", id=user),
                }
                for k in snips
            ],
        }
    ]

    return jsonify(response)

MySnippetsApi

Bases: Resource

Requests against the Snippet model to api/users/<id>/snippets

Source code in resources/profile.py
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
class MySnippetsApi(Resource):
    """Requests against the Snippet model to `api/users/<id>/snippets`"""

    def get(self, id):
        """Retrieve a complete list of all Snippets created by a user.

        Yields:
            Identify a User object against a User model via username (id).
            jsonify a Query object to the Snippets database of all
            Snippet objects with field `addedBy` equal to the User
            model's unique username.

        Returns:
            [{dict}]: JSON Flask Response
            A complete list of Snippet objects, with all nested fields
            dereferenced.
        Note:
            This endpoint is the primary endpoint for fetching User's
            Snippets profile.
        """
        user = User.objects.get(username=id)
        snippets = Snippet.objects(addedBy=user).order_by("-addedOn")
        resp = [
            {
                "_id": str(ObjectId(doc["id"])),
                "title": doc["title"],
                "filename": doc["filename"],
                "description": doc["description"],
                "language": doc["language"],
                "value": doc["value"],
                "addedBy": doc["addedBy"]["username"],
                "likedBy": [elem["username"] for elem in doc["likedBy"]],
                "tags": doc["tags"],
                "addedOn": doc["addedOn"],
                "updatedOn": doc["updatedOn"],
                "private": doc["private"],
                "source": doc["source"],
                "score": doc["score"],
                "url": url_for("snippetapi", id=str(ObjectId(doc["id"]))),
            }
            for doc in snippets
        ]

        return jsonify(resp)

get(id)

Retrieve a complete list of all Snippets created by a user.

Yields:

Type Description

Identify a User object against a User model via username (id).

jsonify a Query object to the Snippets database of all

Snippet objects with field addedBy equal to the User

model's unique username.

Returns:

Type Description

[{dict}]: JSON Flask Response

A complete list of Snippet objects, with all nested fields

dereferenced.

Note

This endpoint is the primary endpoint for fetching User's Snippets profile.

Source code in resources/profile.py
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
def get(self, id):
    """Retrieve a complete list of all Snippets created by a user.

    Yields:
        Identify a User object against a User model via username (id).
        jsonify a Query object to the Snippets database of all
        Snippet objects with field `addedBy` equal to the User
        model's unique username.

    Returns:
        [{dict}]: JSON Flask Response
        A complete list of Snippet objects, with all nested fields
        dereferenced.
    Note:
        This endpoint is the primary endpoint for fetching User's
        Snippets profile.
    """
    user = User.objects.get(username=id)
    snippets = Snippet.objects(addedBy=user).order_by("-addedOn")
    resp = [
        {
            "_id": str(ObjectId(doc["id"])),
            "title": doc["title"],
            "filename": doc["filename"],
            "description": doc["description"],
            "language": doc["language"],
            "value": doc["value"],
            "addedBy": doc["addedBy"]["username"],
            "likedBy": [elem["username"] for elem in doc["likedBy"]],
            "tags": doc["tags"],
            "addedOn": doc["addedOn"],
            "updatedOn": doc["updatedOn"],
            "private": doc["private"],
            "source": doc["source"],
            "score": doc["score"],
            "url": url_for("snippetapi", id=str(ObjectId(doc["id"]))),
        }
        for doc in snippets
    ]

    return jsonify(resp)

MySnippetsOptionsApi

Bases: Resource

Requests against the Snippet model to api/users/<user_id>/snippets/options

Source code in resources/profile.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
class MySnippetsOptionsApi(Resource):
    """Requests against the Snippet model to `api/users/<user_id>/snippets/options`"""

    def get(self, user_id):
        """Retrieve an array of all Snippets available to the user.

        Yields:
            Identify a User object against a User model via username (user_id).
            jsonify a Query object to the Snippet database of all
            Snippet objects with field `addedBy` equal to the User
            model via unique username `user_id`, formatted as `options` in
            an HTML `select` element.

        Returns:
            [{dict}]: JSON Flask Response
                array of Snippets with `label` and `value` keys for `Select` UI.
        Note:
            This key endpoint is what allows the frontend to present documents
            as creatable and/or multi-select options in an instant following live
            and/or recurrent updates and additions to a user's saved Snippets.
        """
        user = User.objects.get(username=user_id)
        snippets = Snippet.objects(addedBy=user)
        response = [
            {"label": doc["title"], "value": str(ObjectId(doc["id"]))}
            for doc in snippets
        ]

        return jsonify(response)

get(user_id)

Retrieve an array of all Snippets available to the user.

Yields:

Type Description

Identify a User object against a User model via username (user_id).

jsonify a Query object to the Snippet database of all

Snippet objects with field addedBy equal to the User

model via unique username user_id, formatted as options in

an HTML select element.

Returns:

Type Description

[{dict}]: JSON Flask Response array of Snippets with label and value keys for Select UI.

Note

This key endpoint is what allows the frontend to present documents as creatable and/or multi-select options in an instant following live and/or recurrent updates and additions to a user's saved Snippets.

Source code in resources/profile.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def get(self, user_id):
    """Retrieve an array of all Snippets available to the user.

    Yields:
        Identify a User object against a User model via username (user_id).
        jsonify a Query object to the Snippet database of all
        Snippet objects with field `addedBy` equal to the User
        model via unique username `user_id`, formatted as `options` in
        an HTML `select` element.

    Returns:
        [{dict}]: JSON Flask Response
            array of Snippets with `label` and `value` keys for `Select` UI.
    Note:
        This key endpoint is what allows the frontend to present documents
        as creatable and/or multi-select options in an instant following live
        and/or recurrent updates and additions to a user's saved Snippets.
    """
    user = User.objects.get(username=user_id)
    snippets = Snippet.objects(addedBy=user)
    response = [
        {"label": doc["title"], "value": str(ObjectId(doc["id"]))}
        for doc in snippets
    ]

    return jsonify(response)

UserApi

Bases: Resource

Requests against the User model to api/users/<id>

Source code in resources/user.py
 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
class UserApi(Resource):
    """Requests against the User model to `api/users/<id>`"""

    def get(self, id):
        """Returns a user object with username matching id."""

        try:
            user = []
            for doc in User.objects(username=id):
                user.append(
                    {
                        "_id": str(ObjectId(doc["id"])),
                        "username": doc["username"],
                        "online": doc["online"],
                        "snippets_created": [
                            {
                                "snippet_title": k["title"],
                                "snippet_id": str(ObjectId(k["id"])),
                            }
                            for k in doc["snippets_created"]
                        ],
                        "snippets_liked": [
                            {
                                "snippet_title": k["title"],
                                "snippet_id": str(ObjectId(k["id"])),
                            }
                            for k in doc["snippets_liked"]
                        ],
                        "collections": [
                            {
                                "collection_name": k["name"],
                                "collection_id": str(ObjectId(k["id"])),
                            }
                            for k in doc["collections"]
                        ],
                    }
                )
            return jsonify(user)

        except DoesNotExist:
            raise UserNotExistsError
        except Exception:
            raise InternalServerError

    @jwt_required()
    def put(self):
        """Update one User object with a matching id.

        Raises:
            Schema validation errors.
            If required fields are missing.
        Returns: {dict}
            JSON Flask Response, 200
                else: Notifies the frontend with status code and message.
        """
        try:
            user_id = get_jwt_identity()
            body = request.get_json()
            User.objects.get(username=user_id).update(**body)
            return {"message": "Profile updated"}, 200
        except InvalidQueryError:
            raise SchemaValidationError
        except Exception:
            raise InternalServerError

    @jwt_required()
    def delete(self, id):
        """Delete one User object with a matching id.

        Returns: {dict}
            JSON Flask Response, 200
                with status message.
        """

        try:
            user_id = get_jwt_identity()
            user = User.objects.get(username=user_id)
            user.delete()
            return {"message": "User deleted"}, 200
        except Exception:
            raise InternalServerError

delete(id)

Delete one User object with a matching id.

{dict}

Type Description

JSON Flask Response, 200 with status message.

Source code in resources/user.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@jwt_required()
def delete(self, id):
    """Delete one User object with a matching id.

    Returns: {dict}
        JSON Flask Response, 200
            with status message.
    """

    try:
        user_id = get_jwt_identity()
        user = User.objects.get(username=user_id)
        user.delete()
        return {"message": "User deleted"}, 200
    except Exception:
        raise InternalServerError

get(id)

Returns a user object with username matching id.

Source code in resources/user.py
 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
def get(self, id):
    """Returns a user object with username matching id."""

    try:
        user = []
        for doc in User.objects(username=id):
            user.append(
                {
                    "_id": str(ObjectId(doc["id"])),
                    "username": doc["username"],
                    "online": doc["online"],
                    "snippets_created": [
                        {
                            "snippet_title": k["title"],
                            "snippet_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["snippets_created"]
                    ],
                    "snippets_liked": [
                        {
                            "snippet_title": k["title"],
                            "snippet_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["snippets_liked"]
                    ],
                    "collections": [
                        {
                            "collection_name": k["name"],
                            "collection_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["collections"]
                    ],
                }
            )
        return jsonify(user)

    except DoesNotExist:
        raise UserNotExistsError
    except Exception:
        raise InternalServerError

put()

Update one User object with a matching id.

{dict}

Type Description

JSON Flask Response, 200 else: Notifies the frontend with status code and message.

Source code in resources/user.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@jwt_required()
def put(self):
    """Update one User object with a matching id.

    Raises:
        Schema validation errors.
        If required fields are missing.
    Returns: {dict}
        JSON Flask Response, 200
            else: Notifies the frontend with status code and message.
    """
    try:
        user_id = get_jwt_identity()
        body = request.get_json()
        User.objects.get(username=user_id).update(**body)
        return {"message": "Profile updated"}, 200
    except InvalidQueryError:
        raise SchemaValidationError
    except Exception:
        raise InternalServerError

UsersApi

Bases: Resource

Requests against the User model to api/users

Source code in resources/user.py
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
class UsersApi(Resource):
    """Requests against the User model to `api/users`"""

    def get(self):
        """Returns an array of all User objects."""

        users = []
        for doc in User.objects():
            users.append(
                {
                    "_id": str(doc["id"]),
                    "username": doc["username"],
                    "online": doc["online"],
                    "snippets_created": [
                        {
                            "snippet_title": k["title"],
                            "snippet_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["snippets_created"]
                    ],
                    "snippets_liked": [
                        {
                            "snippet_title": k["title"],
                            "snippet_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["snippets_liked"]
                    ],
                    "collections": [
                        {
                            "collection_name": k["name"],
                            "collection_id": str(ObjectId(k["id"])),
                        }
                        for k in doc["collections"]
                    ],
                }
            )

        return jsonify(users)

get()

Returns an array of all User objects.

Source code in resources/user.py
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
def get(self):
    """Returns an array of all User objects."""

    users = []
    for doc in User.objects():
        users.append(
            {
                "_id": str(doc["id"]),
                "username": doc["username"],
                "online": doc["online"],
                "snippets_created": [
                    {
                        "snippet_title": k["title"],
                        "snippet_id": str(ObjectId(k["id"])),
                    }
                    for k in doc["snippets_created"]
                ],
                "snippets_liked": [
                    {
                        "snippet_title": k["title"],
                        "snippet_id": str(ObjectId(k["id"])),
                    }
                    for k in doc["snippets_liked"]
                ],
                "collections": [
                    {
                        "collection_name": k["name"],
                        "collection_id": str(ObjectId(k["id"])),
                    }
                    for k in doc["collections"]
                ],
            }
        )

    return jsonify(users)

ForgotPassword

Bases: Resource

This class is a subclass of the Resource class, and it's used to handle the forgot password functionality.

Source code in resources/reset_password.py
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
class ForgotPassword(Resource):
    """This class is a subclass of the Resource class, and it's used to handle the forgot password functionality."""

    @staticmethod
    def post(self):
        """
        The post function is used to send an email with a link that will allow the user to reset their password.
        The function takes in an email and checks if it exists in the database. If it does, then a token is generated
        and sent to the user's email address along with instructions on how to reset their password.

        Args:
            self: Reference the current instance of the class

        Returns:
            A response with a message that the email was sent

        """

        url = request.host_url + "reset/"
        try:
            body = request.get_json()
            email = body.get("email")
            if not email:
                raise SchemaValidationError

            user = User.objects.get(email=email)
            if not user:
                raise EmailDoesNotExistError

            expires = datetime.timedelta(hours=24)
            reset_token = create_access_token(str(user.id), expires_delta=expires)

            return send_email(
                "[Cheat-hub] Reset Your Password",
                sender="israelias.js@gmail.com",
                recipients=[user.email],
                text_body=render_template("reset_password.txt", url=url + reset_token),
                html_body=render_template("reset_password.html", url=url + reset_token),
            )
        except SchemaValidationError:
            raise SchemaValidationError
        except EmailDoesNotExistError:
            raise EmailDoesNotExistError
        except Exception as e:
            raise InternalServerError

post() staticmethod

The post function is used to send an email with a link that will allow the user to reset their password. The function takes in an email and checks if it exists in the database. If it does, then a token is generated and sent to the user's email address along with instructions on how to reset their password.

Parameters:

Name Type Description Default
self

Reference the current instance of the class

required

Returns:

Type Description

A response with a message that the email was sent

Source code in resources/reset_password.py
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
@staticmethod
def post(self):
    """
    The post function is used to send an email with a link that will allow the user to reset their password.
    The function takes in an email and checks if it exists in the database. If it does, then a token is generated
    and sent to the user's email address along with instructions on how to reset their password.

    Args:
        self: Reference the current instance of the class

    Returns:
        A response with a message that the email was sent

    """

    url = request.host_url + "reset/"
    try:
        body = request.get_json()
        email = body.get("email")
        if not email:
            raise SchemaValidationError

        user = User.objects.get(email=email)
        if not user:
            raise EmailDoesNotExistError

        expires = datetime.timedelta(hours=24)
        reset_token = create_access_token(str(user.id), expires_delta=expires)

        return send_email(
            "[Cheat-hub] Reset Your Password",
            sender="israelias.js@gmail.com",
            recipients=[user.email],
            text_body=render_template("reset_password.txt", url=url + reset_token),
            html_body=render_template("reset_password.html", url=url + reset_token),
        )
    except SchemaValidationError:
        raise SchemaValidationError
    except EmailDoesNotExistError:
        raise EmailDoesNotExistError
    except Exception as e:
        raise InternalServerError

ResetPassword

Bases: Resource

This class is a subclass of the Resource class from the Flask-RESTful library. It has a post method that takes in a JSON object with a username and password. It then checks if the username is in the database and if it is, it updates the password.

Source code in resources/reset_password.py
 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
class ResetPassword(Resource):
    """This class is a subclass of the Resource class from the Flask-RESTful library. It has a post method that takes in a JSON
    object with a username and password. It then checks if the username is in the database and if it is, it updates the
    password."""

    def post(self):
        """
        The post function is used to reset a user's password. It takes in the
        reset_token and password from the request body, and then checks if they are
        valid. If they are valid, it will update the user's password in MongoDB.

        Args:
            self: Reference the current instance of the class

        Returns:
            A message that password reset was successful
        """

        url = request.host_url + "reset/"
        try:
            body = request.get_json()
            reset_token = body.get("reset_token")
            password = body.get("password")

            if not reset_token or not password:
                raise SchemaValidationError

            user_id = decode_token(reset_token)["sub"]
            user = User.objects.get(id=user_id)

            user.modify(password=password)
            user.hash_password()
            user.save()

            return send_email(
                "[Cheat-hub] Password reset successful",
                sender="support@cheat-hub.com",
                recipients=[user.email],
                text_body="Password reset was successful",
                html_body="<p>Password reset was successful</p>",
            )

        except SchemaValidationError:
            raise SchemaValidationError
        except ExpiredSignatureError:
            raise ExpiredTokenError
        except (DecodeError, InvalidTokenError):
            raise BadTokenError
        except Exception as e:
            raise InternalServerError

post()

The post function is used to reset a user's password. It takes in the reset_token and password from the request body, and then checks if they are valid. If they are valid, it will update the user's password in MongoDB.

Parameters:

Name Type Description Default
self

Reference the current instance of the class

required

Returns:

Type Description

A message that password reset was successful

Source code in resources/reset_password.py
 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
def post(self):
    """
    The post function is used to reset a user's password. It takes in the
    reset_token and password from the request body, and then checks if they are
    valid. If they are valid, it will update the user's password in MongoDB.

    Args:
        self: Reference the current instance of the class

    Returns:
        A message that password reset was successful
    """

    url = request.host_url + "reset/"
    try:
        body = request.get_json()
        reset_token = body.get("reset_token")
        password = body.get("password")

        if not reset_token or not password:
            raise SchemaValidationError

        user_id = decode_token(reset_token)["sub"]
        user = User.objects.get(id=user_id)

        user.modify(password=password)
        user.hash_password()
        user.save()

        return send_email(
            "[Cheat-hub] Password reset successful",
            sender="support@cheat-hub.com",
            recipients=[user.email],
            text_body="Password reset was successful",
            html_body="<p>Password reset was successful</p>",
        )

    except SchemaValidationError:
        raise SchemaValidationError
    except ExpiredSignatureError:
        raise ExpiredTokenError
    except (DecodeError, InvalidTokenError):
        raise BadTokenError
    except Exception as e:
        raise InternalServerError

TagsApi

Bases: Resource

Prepares all selectable tags: api/tags.

Source code in resources/tags.py
17
18
19
20
21
22
23
24
class TagsApi(Resource):
    """Prepares all selectable tags: api/tags."""

    def get(self):
        """Retrieve a all current tags."""

        all_tags_arr = all_tags()
        return jsonify([{"label": tag, "value": tag} for tag in all_tags_arr])

get()

Retrieve a all current tags.

Source code in resources/tags.py
20
21
22
23
24
def get(self):
    """Retrieve a all current tags."""

    all_tags_arr = all_tags()
    return jsonify([{"label": tag, "value": tag} for tag in all_tags_arr])

SearchApi

Bases: Resource

Handles query, language and tag params in URL search endpoint: api/search.

Source code in resources/search.py
 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
188
189
190
191
class SearchApi(Resource):
    """Handles query, language and tag params in URL search endpoint: api/search."""

    def get(self):
        """Retrieve a paginated list of public snippets.

        Yields:
            `/api/search?`
            The base url.
            The URL string should follow this order:

            `query=hello%20world`
            Search query is required.
            The following params [language, tags, page] are optional, and are there to narrow the search.

            `&language=python`
            Language query hones search query down to a language.
            Frontend can call {language=a}
            If empty, params for search query will prevail, and all languages will return.

            `tags=javascript&tags=jquery`
            Tags query appends to a list.
            Frontend can append {tags=a&tags=b&tags=c} multiple times, and the parser will parse:
            [a, b, c]

            ` &page=1`
            Page param will be available authomatically.

        Raises:
            SnippetNotExistsError: The Snippet does not exist.
            InternalServerError: Server error.

        Returns:
            [{dict}]: JSON Flask Response
                array of Snippets that match a query
        """
        try:
            search_request = search_parser.parse_args()
            search = search_request["query"]

            language_request = language_parser.parse_args()
            language = language_request["language"]

            tag_request = tag_parser.parse_args()
            tags = tag_request["tags"]

            page_request = pagination_parser.parse_args()
            page = page_request["page"]
            per_page = page_request["per_page"]

            all_langs_arr = all_languages()
            all_tags_arr = all_tags()

            if len(search) == 0:
                query = (
                    Snippet.objects(
                        language__in=[language] if language else all_langs_arr,
                        tags__in=tags if tags else all_tags_arr,
                    )
                    .order_by("-addedOn")
                    .paginate(
                        page=page,
                        per_page=per_page,
                    )
                )
                links = pagination_links(
                    query, language=language, tags=tags, resource="searchapi"
                )
                resp = {
                    "links": links,
                    "has_prev": query.has_prev,
                    "has_next": query.has_next,
                    "page": query.page,
                    "total_pages": query.pages,
                    "items_per_page": query.per_page,
                    "total_items": query.total,
                    "items": [
                        {
                            "_id": str(ObjectId(k["id"])),
                            "title": k["title"],
                            "filename": k["filename"],
                            "description": k["description"],
                            "language": k["language"],
                            "value": k["value"],
                            "addedBy": k["addedBy"]["username"],
                            "likedBy": [elem["username"] for elem in k["likedBy"]],
                            "tags": k["tags"],
                            "addedOn": k["addedOn"],
                            "updatedOn": k["updatedOn"],
                            "private": k["private"],
                            "source": k["source"],
                            "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
                        }
                        for k in query.items
                    ],
                }

                return jsonify(resp)

            else:

                query = (
                    Snippet.objects()
                    .search_text(search, language="en")
                    .order_by("-addedOn")
                    .paginate(
                        page=page,
                        per_page=per_page,
                    )
                )

                meta = pagination_meta(query)
                links = pagination_links(
                    query,
                    query=search,
                    language=language,
                    tags=tags,
                    resource="searchapi",
                )

                resp = {
                    "links": links,
                    "has_prev": query.has_prev,
                    "has_next": query.has_next,
                    "page": query.page,
                    "total_pages": query.pages,
                    "items_per_page": query.per_page,
                    "total_items": query.total,
                    "items": [
                        {
                            "_id": str(ObjectId(k["id"])),
                            "title": k["title"],
                            "filename": k["filename"],
                            "description": k["description"],
                            "language": k["language"],
                            "value": k["value"],
                            "addedBy": k["addedBy"]["username"],
                            "likedBy": [elem["username"] for elem in k["likedBy"]],
                            "tags": k["tags"],
                            "addedOn": k["addedOn"],
                            "updatedOn": k["updatedOn"],
                            "private": k["private"],
                            "source": k["source"],
                            "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
                        }
                        for k in query.items
                    ],
                }

            return jsonify(resp)
        except DoesNotExist:
            raise SnippetNotExistsError
        except Exception:
            raise InternalServerError

get()

Retrieve a paginated list of public snippets.

Yields:

Type Description

/api/search?

The base url.

The URL string should follow this order:

query=hello%20world

Search query is required.

The following params [language, tags, page] are optional, and are there to narrow the search.

&language=python

Language query hones search query down to a language.

Frontend can call {language=a}

If empty, params for search query will prevail, and all languages will return.

tags=javascript&tags=jquery

Tags query appends to a list.

Frontend can append {tags=a&tags=b&tags=c} multiple times, and the parser will parse:

[a, b, c]

&page=1

Page param will be available authomatically.

Raises:

Type Description
SnippetNotExistsError

The Snippet does not exist.

InternalServerError

Server error.

Returns:

Type Description

[{dict}]: JSON Flask Response array of Snippets that match a query

Source code in resources/search.py
 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
188
189
190
191
def get(self):
    """Retrieve a paginated list of public snippets.

    Yields:
        `/api/search?`
        The base url.
        The URL string should follow this order:

        `query=hello%20world`
        Search query is required.
        The following params [language, tags, page] are optional, and are there to narrow the search.

        `&language=python`
        Language query hones search query down to a language.
        Frontend can call {language=a}
        If empty, params for search query will prevail, and all languages will return.

        `tags=javascript&tags=jquery`
        Tags query appends to a list.
        Frontend can append {tags=a&tags=b&tags=c} multiple times, and the parser will parse:
        [a, b, c]

        ` &page=1`
        Page param will be available authomatically.

    Raises:
        SnippetNotExistsError: The Snippet does not exist.
        InternalServerError: Server error.

    Returns:
        [{dict}]: JSON Flask Response
            array of Snippets that match a query
    """
    try:
        search_request = search_parser.parse_args()
        search = search_request["query"]

        language_request = language_parser.parse_args()
        language = language_request["language"]

        tag_request = tag_parser.parse_args()
        tags = tag_request["tags"]

        page_request = pagination_parser.parse_args()
        page = page_request["page"]
        per_page = page_request["per_page"]

        all_langs_arr = all_languages()
        all_tags_arr = all_tags()

        if len(search) == 0:
            query = (
                Snippet.objects(
                    language__in=[language] if language else all_langs_arr,
                    tags__in=tags if tags else all_tags_arr,
                )
                .order_by("-addedOn")
                .paginate(
                    page=page,
                    per_page=per_page,
                )
            )
            links = pagination_links(
                query, language=language, tags=tags, resource="searchapi"
            )
            resp = {
                "links": links,
                "has_prev": query.has_prev,
                "has_next": query.has_next,
                "page": query.page,
                "total_pages": query.pages,
                "items_per_page": query.per_page,
                "total_items": query.total,
                "items": [
                    {
                        "_id": str(ObjectId(k["id"])),
                        "title": k["title"],
                        "filename": k["filename"],
                        "description": k["description"],
                        "language": k["language"],
                        "value": k["value"],
                        "addedBy": k["addedBy"]["username"],
                        "likedBy": [elem["username"] for elem in k["likedBy"]],
                        "tags": k["tags"],
                        "addedOn": k["addedOn"],
                        "updatedOn": k["updatedOn"],
                        "private": k["private"],
                        "source": k["source"],
                        "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
                    }
                    for k in query.items
                ],
            }

            return jsonify(resp)

        else:

            query = (
                Snippet.objects()
                .search_text(search, language="en")
                .order_by("-addedOn")
                .paginate(
                    page=page,
                    per_page=per_page,
                )
            )

            meta = pagination_meta(query)
            links = pagination_links(
                query,
                query=search,
                language=language,
                tags=tags,
                resource="searchapi",
            )

            resp = {
                "links": links,
                "has_prev": query.has_prev,
                "has_next": query.has_next,
                "page": query.page,
                "total_pages": query.pages,
                "items_per_page": query.per_page,
                "total_items": query.total,
                "items": [
                    {
                        "_id": str(ObjectId(k["id"])),
                        "title": k["title"],
                        "filename": k["filename"],
                        "description": k["description"],
                        "language": k["language"],
                        "value": k["value"],
                        "addedBy": k["addedBy"]["username"],
                        "likedBy": [elem["username"] for elem in k["likedBy"]],
                        "tags": k["tags"],
                        "addedOn": k["addedOn"],
                        "updatedOn": k["updatedOn"],
                        "private": k["private"],
                        "source": k["source"],
                        "url": url_for("snippetapi", id=str(ObjectId(k["id"]))),
                    }
                    for k in query.items
                ],
            }

        return jsonify(resp)
    except DoesNotExist:
        raise SnippetNotExistsError
    except Exception:
        raise InternalServerError