We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
The ability to delete my account.
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->I had this app mistaken for something else, and I would like to delete my account. However, there doesn't seem to be an easy way to do that, and the only way to contact you according to your website (aside from social media, which I don't have) is Github.

**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
Allow somebody to erase their account via a button on their Profile. Or better yet, just delete my account so I can forget about this already.

**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->I don't know what else to do, this seems like a very basic function for an app to have.

**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->
Thank you.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/api/users.py`
Content:
```
1 import base64
2 
3 from flask import Blueprint, request, jsonify, abort, make_response
4 from flask_jwt import current_identity as current_user
5 from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship
6 from sqlalchemy.orm.exc import NoResultFound
7 import urllib.error
8 
9 from app import get_settings
10 from app.api.bootstrap import api
11 from app.api.helpers.db import safe_query, get_count
12 from app.api.helpers.exceptions import ConflictException, UnprocessableEntity, ForbiddenException
13 from app.api.helpers.files import create_save_image_sizes, make_frontend_url
14 from app.api.helpers.mail import send_email_confirmation, send_email_change_user_email, send_email_with_action
15 from app.api.helpers.permission_manager import has_access
16 from app.api.helpers.permissions import is_user_itself
17 from app.api.helpers.utilities import get_serializer, str_generator
18 from app.api.schema.users import UserSchema, UserSchemaPublic
19 from app.models import db
20 from app.models.access_code import AccessCode
21 from app.models.discount_code import DiscountCode
22 from app.models.email_notification import EmailNotification
23 from app.models.event_invoice import EventInvoice
24 from app.models.feedback import Feedback
25 from app.models.mail import USER_REGISTER_WITH_PASSWORD, PASSWORD_RESET_AND_VERIFY
26 from app.models.notification import Notification
27 from app.models.session import Session
28 from app.models.speaker import Speaker
29 from app.models.ticket_holder import TicketHolder
30 from app.models.user import User
31 from app.models.users_events_role import UsersEventsRoles
32 
33 user_misc_routes = Blueprint('user_misc', __name__, url_prefix='/v1')
34 
35 
36 class UserList(ResourceList):
37     """
38     List and create Users
39     """
40 
41     def before_create_object(self, data, view_kwargs):
42         """
43         method to check if there is an existing user with same email which is received in data to create a new user
44         and if the password is at least 8 characters long
45         :param data:
46         :param view_kwargs:
47         :return:
48         """
49         if len(data['password']) < 8:
50             raise UnprocessableEntity({'source': '/data/attributes/password'},
51                                        'Password should be at least 8 characters long')
52         if db.session.query(User.id).filter_by(email=data['email'].strip()).scalar() is not None:
53             raise ConflictException({'pointer': '/data/attributes/email'}, "Email already exists")
54 
55     def after_create_object(self, user, data, view_kwargs):
56         """
57         method to send-
58         email notification
59         mail link for register verification
60         add image urls
61         :param user:
62         :param data:
63         :param view_kwargs:
64         :return:
65         """
66 
67         if user.was_registered_with_order:
68             link = make_frontend_url('/reset-password', {'token': user.reset_password})
69             send_email_with_action(user, PASSWORD_RESET_AND_VERIFY, app_name=get_settings()['app_name'],
70                                    email=user.email, link=link)
71         else:
72             s = get_serializer()
73             hash = str(base64.b64encode(str(s.dumps([user.email, str_generator()])).encode()), 'utf-8')
74             link = make_frontend_url('/verify'.format(id=user.id), {'token': hash})
75             send_email_with_action(user, USER_REGISTER_WITH_PASSWORD, app_name=get_settings()['app_name'],
76                                    email=user.email)
77             send_email_confirmation(user.email, link)
78         # TODO Handle in a celery task
79         # if data.get('original_image_url'):
80         #     try:
81         #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)
82         #     except (urllib.error.HTTPError, urllib.error.URLError):
83         #         raise UnprocessableEntity(
84         #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'
85         #         )
86         #     uploaded_images['small_image_url'] = uploaded_images['thumbnail_image_url']
87         #     del uploaded_images['large_image_url']
88         #     self.session.query(User).filter_by(id=user.id).update(uploaded_images)
89 
90         if data.get('avatar_url'):
91             start_image_resizing_tasks(user, data['avatar_url'])
92 
93     decorators = (api.has_permission('is_admin', methods="GET"),)
94     schema = UserSchema
95     data_layer = {'session': db.session,
96                   'model': User,
97                   'methods': {
98                       'before_create_object': before_create_object,
99                       'after_create_object': after_create_object
100                   }}
101 
102 
103 class UserDetail(ResourceDetail):
104     """
105     User detail by id
106     """
107 
108     def before_get(self, args, kwargs):
109 
110         if current_user.is_admin or current_user.is_super_admin or current_user:
111             self.schema = UserSchema
112         else:
113             self.schema = UserSchemaPublic
114 
115     def before_get_object(self, view_kwargs):
116         """
117         before get method for user object
118         :param view_kwargs:
119         :return:
120         """
121         if view_kwargs.get('notification_id') is not None:
122             notification = safe_query(self, Notification, 'id', view_kwargs['notification_id'], 'notification_id')
123             if notification.user_id is not None:
124                 view_kwargs['id'] = notification.user_id
125             else:
126                 view_kwargs['id'] = None
127 
128         if view_kwargs.get('feedback_id') is not None:
129             feedback = safe_query(self, Feedback, 'id', view_kwargs['feedback_id'], 'feedback_id')
130             if feedback.user_id is not None:
131                 view_kwargs['id'] = feedback.user_id
132             else:
133                 view_kwargs['id'] = None
134 
135         if view_kwargs.get('attendee_id') is not None:
136             attendee = safe_query(self, TicketHolder, 'id', view_kwargs['attendee_id'], 'attendee_id')
137             if attendee.user is not None:
138                 if (not has_access('is_user_itself',
139                                    user_id=attendee.user.id) or not has_access('is_coorganizer',
140                                                                                event_id=attendee.event_id)):
141                     raise ForbiddenException({'source': ''}, 'Access Forbidden')
142                 view_kwargs['id'] = attendee.user.id
143             else:
144                 view_kwargs['id'] = None
145 
146         if view_kwargs.get('event_invoice_id') is not None:
147             event_invoice = safe_query(self, EventInvoice, 'id', view_kwargs['event_invoice_id'], 'event_invoice_id')
148             if event_invoice.user_id is not None:
149                 view_kwargs['id'] = event_invoice.user_id
150             else:
151                 view_kwargs['id'] = None
152 
153         if view_kwargs.get('users_events_role_id') is not None:
154             users_events_role = safe_query(self, UsersEventsRoles, 'id', view_kwargs['users_events_role_id'],
155                                            'users_events_role_id')
156             if users_events_role.user_id is not None:
157                 view_kwargs['id'] = users_events_role.user_id
158             else:
159                 view_kwargs['id'] = None
160 
161         if view_kwargs.get('speaker_id') is not None:
162             speaker = safe_query(self, Speaker, 'id', view_kwargs['speaker_id'], 'speaker_id')
163             if speaker.user_id is not None:
164                 view_kwargs['id'] = speaker.user_id
165             else:
166                 view_kwargs['id'] = None
167 
168         if view_kwargs.get('session_id') is not None:
169             session = safe_query(self, Session, 'id', view_kwargs['session_id'], 'session_id')
170             if session.creator_id is not None:
171                 view_kwargs['id'] = session.creator_id
172             else:
173                 view_kwargs['id'] = None
174 
175         if view_kwargs.get('access_code_id') is not None:
176             access_code = safe_query(self, AccessCode, 'id', view_kwargs['access_code_id'], 'access_code_id')
177             if access_code.marketer_id is not None:
178                 view_kwargs['id'] = access_code.marketer_id
179             else:
180                 view_kwargs['id'] = None
181 
182         if view_kwargs.get('discount_code_id') is not None:
183             discount_code = safe_query(self, DiscountCode, 'id', view_kwargs['discount_code_id'], 'discount_code_id')
184             if discount_code.marketer_id is not None:
185                 view_kwargs['id'] = discount_code.marketer_id
186             else:
187                 view_kwargs['id'] = None
188 
189         if view_kwargs.get('email_notification_id') is not None:
190             email_notification = safe_query(self, EmailNotification, 'id', view_kwargs['email_notification_id'],
191                                             'email_notification_id')
192             if email_notification.user_id is not None:
193                 view_kwargs['id'] = email_notification.user_id
194             else:
195                 view_kwargs['id'] = None
196 
197     def before_update_object(self, user, data, view_kwargs):
198         # TODO: Make a celery task for this
199         # if data.get('avatar_url') and data['original_image_url'] != user.original_image_url:
200         #     try:
201         #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)
202         #     except (urllib.error.HTTPError, urllib.error.URLError):
203         #         raise UnprocessableEntity(
204         #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'
205         #         )
206         #     data['original_image_url'] = uploaded_images['original_image_url']
207         #     data['small_image_url'] = uploaded_images['thumbnail_image_url']
208         #     data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url']
209         #     data['icon_image_url'] = uploaded_images['icon_image_url']
210         users_email = data.get('email', None)
211         if users_email is not None:
212             users_email = users_email.strip()
213 
214         if has_access('is_admin') and data.get('deleted_at') != user.deleted_at:
215             user.deleted_at = data.get('deleted_at')
216 
217         if users_email is not None and users_email != user.email:
218             try:
219                 db.session.query(User).filter_by(email=users_email).one()
220             except NoResultFound:
221                 view_kwargs['email_changed'] = user.email
222             else:
223                 raise ConflictException({'pointer': '/data/attributes/email'}, "Email already exists")
224 
225         if has_access('is_super_admin') and data.get('is_admin') and data.get('is_admin') != user.is_admin:
226             user.is_admin = not user.is_admin
227 
228         if has_access('is_admin') and ('is_sales_admin' in data) and data.get('is_sales_admin') != user.is_sales_admin:
229             user.is_sales_admin = not user.is_sales_admin
230 
231         if has_access('is_admin') and ('us_marketer' in data) and data.get('is_marketer') != user.is_marketer:
232             user.is_marketer = not user.is_marketer
233 
234         if data.get('avatar_url'):
235             start_image_resizing_tasks(user, data['avatar_url'])
236 
237     def after_update_object(self, user, data, view_kwargs):
238         """
239         method to mail user about email change
240         :param user:
241         :param data:
242         :param view_kwargs:
243         :return:
244         """
245         if view_kwargs.get('email_changed'):
246             send_email_change_user_email(user, view_kwargs.get('email_changed'))
247 
248     decorators = (api.has_permission('is_user_itself', fetch="user_id,id", fetch_as="user_id",
249                                      model=[Notification, Feedback, UsersEventsRoles, Session, EventInvoice, AccessCode,
250                                             DiscountCode, EmailNotification, Speaker, User],
251                                      fetch_key_url="notification_id, feedback_id, users_events_role_id, session_id, \
252                   event_invoice_id, access_code_id, discount_code_id, email_notification_id, speaker_id, id",
253                                      leave_if=lambda a: a.get('attendee_id')),)
254     schema = UserSchema
255     data_layer = {'session': db.session,
256                   'model': User,
257                   'methods': {
258                       'before_get_object': before_get_object,
259                       'before_update_object': before_update_object,
260                       'after_update_object': after_update_object
261                   }}
262 
263 
264 class UserRelationship(ResourceRelationship):
265     """
266     User Relationship
267     """
268     decorators = (is_user_itself,)
269     schema = UserSchema
270     data_layer = {'session': db.session,
271                   'model': User}
272 
273 
274 @user_misc_routes.route('/users/checkEmail', methods=['POST'])
275 def is_email_available():
276     email = request.json.get('email', None)
277     if email:
278         if get_count(db.session.query(User).filter_by(email=email)):
279             return jsonify(
280                 result="False"
281             )
282         else:
283             return jsonify(
284                 result="True"
285             )
286     else:
287         abort(
288             make_response(jsonify(error="Email field missing"), 422)
289         )
290 
291 
292 def start_image_resizing_tasks(user, original_image_url):
293     user_id = str(user.id)
294     from .helpers.tasks import resize_user_images_task
295     resize_user_images_task.delay(user_id, original_image_url)
296
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/app/api/users.py b/app/api/users.py
--- a/app/api/users.py
+++ b/app/api/users.py
@@ -214,6 +214,14 @@
         if has_access('is_admin') and data.get('deleted_at') != user.deleted_at:
             user.deleted_at = data.get('deleted_at')
 
+        if has_access('is_user_itself', user_id=user.id) and data.get('deleted_at') != user.deleted_at:
+            if len(user.events) != 0:
+                raise ForbiddenException({'source': ''}, "Users associated with events cannot be deleted")
+            elif len(user.orders) != 0:
+                raise ForbiddenException({'source': ''}, "Users associated with orders cannot be deleted")
+            else:
+                user.deleted_at = data.get('deleted_at')
+
         if users_email is not None and users_email != user.email:
             try:
                 db.session.query(User).filter_by(email=users_email).one()

{"golden_diff": "diff --git a/app/api/users.py b/app/api/users.py\n--- a/app/api/users.py\n+++ b/app/api/users.py\n@@ -214,6 +214,14 @@\n         if has_access('is_admin') and data.get('deleted_at') != user.deleted_at:\n             user.deleted_at = data.get('deleted_at')\n \n+        if has_access('is_user_itself', user_id=user.id) and data.get('deleted_at') != user.deleted_at:\n+            if len(user.events) != 0:\n+                raise ForbiddenException({'source': ''}, \"Users associated with events cannot be deleted\")\n+            elif len(user.orders) != 0:\n+                raise ForbiddenException({'source': ''}, \"Users associated with orders cannot be deleted\")\n+            else:\n+                user.deleted_at = data.get('deleted_at')\n+\n         if users_email is not None and users_email != user.email:\n             try:\n                 db.session.query(User).filter_by(email=users_email).one()\n", "issue": "The ability to delete my account.\n**Is your feature request related to a problem? Please describe.**\r\n<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->I had this app mistaken for something else, and I would like to delete my account. However, there doesn't seem to be an easy way to do that, and the only way to contact you according to your website (aside from social media, which I don't have) is Github.\r\n\r\n**Describe the solution you'd like**\r\n<!-- A clear and concise description of what you want to happen. -->\r\nAllow somebody to erase their account via a button on their Profile. Or better yet, just delete my account so I can forget about this already.\r\n\r\n**Describe alternatives you've considered**\r\n<!-- A clear and concise description of any alternative solutions or features you've considered. -->I don't know what else to do, this seems like a very basic function for an app to have.\r\n\r\n**Additional context**\r\n<!-- Add any other context or screenshots about the feature request here. -->\r\nThank you.\n", "before_files": [{"content": "import base64\n\nfrom flask import Blueprint, request, jsonify, abort, make_response\nfrom flask_jwt import current_identity as current_user\nfrom flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship\nfrom sqlalchemy.orm.exc import NoResultFound\nimport urllib.error\n\nfrom app import get_settings\nfrom app.api.bootstrap import api\nfrom app.api.helpers.db import safe_query, get_count\nfrom app.api.helpers.exceptions import ConflictException, UnprocessableEntity, ForbiddenException\nfrom app.api.helpers.files import create_save_image_sizes, make_frontend_url\nfrom app.api.helpers.mail import send_email_confirmation, send_email_change_user_email, send_email_with_action\nfrom app.api.helpers.permission_manager import has_access\nfrom app.api.helpers.permissions import is_user_itself\nfrom app.api.helpers.utilities import get_serializer, str_generator\nfrom app.api.schema.users import UserSchema, UserSchemaPublic\nfrom app.models import db\nfrom app.models.access_code import AccessCode\nfrom app.models.discount_code import DiscountCode\nfrom app.models.email_notification import EmailNotification\nfrom app.models.event_invoice import EventInvoice\nfrom app.models.feedback import Feedback\nfrom app.models.mail import USER_REGISTER_WITH_PASSWORD, PASSWORD_RESET_AND_VERIFY\nfrom app.models.notification import Notification\nfrom app.models.session import Session\nfrom app.models.speaker import Speaker\nfrom app.models.ticket_holder import TicketHolder\nfrom app.models.user import User\nfrom app.models.users_events_role import UsersEventsRoles\n\nuser_misc_routes = Blueprint('user_misc', __name__, url_prefix='/v1')\n\n\nclass UserList(ResourceList):\n    \"\"\"\n    List and create Users\n    \"\"\"\n\n    def before_create_object(self, data, view_kwargs):\n        \"\"\"\n        method to check if there is an existing user with same email which is received in data to create a new user\n        and if the password is at least 8 characters long\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if len(data['password']) < 8:\n            raise UnprocessableEntity({'source': '/data/attributes/password'},\n                                       'Password should be at least 8 characters long')\n        if db.session.query(User.id).filter_by(email=data['email'].strip()).scalar() is not None:\n            raise ConflictException({'pointer': '/data/attributes/email'}, \"Email already exists\")\n\n    def after_create_object(self, user, data, view_kwargs):\n        \"\"\"\n        method to send-\n        email notification\n        mail link for register verification\n        add image urls\n        :param user:\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n\n        if user.was_registered_with_order:\n            link = make_frontend_url('/reset-password', {'token': user.reset_password})\n            send_email_with_action(user, PASSWORD_RESET_AND_VERIFY, app_name=get_settings()['app_name'],\n                                   email=user.email, link=link)\n        else:\n            s = get_serializer()\n            hash = str(base64.b64encode(str(s.dumps([user.email, str_generator()])).encode()), 'utf-8')\n            link = make_frontend_url('/verify'.format(id=user.id), {'token': hash})\n            send_email_with_action(user, USER_REGISTER_WITH_PASSWORD, app_name=get_settings()['app_name'],\n                                   email=user.email)\n            send_email_confirmation(user.email, link)\n        # TODO Handle in a celery task\n        # if data.get('original_image_url'):\n        #     try:\n        #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)\n        #     except (urllib.error.HTTPError, urllib.error.URLError):\n        #         raise UnprocessableEntity(\n        #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'\n        #         )\n        #     uploaded_images['small_image_url'] = uploaded_images['thumbnail_image_url']\n        #     del uploaded_images['large_image_url']\n        #     self.session.query(User).filter_by(id=user.id).update(uploaded_images)\n\n        if data.get('avatar_url'):\n            start_image_resizing_tasks(user, data['avatar_url'])\n\n    decorators = (api.has_permission('is_admin', methods=\"GET\"),)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User,\n                  'methods': {\n                      'before_create_object': before_create_object,\n                      'after_create_object': after_create_object\n                  }}\n\n\nclass UserDetail(ResourceDetail):\n    \"\"\"\n    User detail by id\n    \"\"\"\n\n    def before_get(self, args, kwargs):\n\n        if current_user.is_admin or current_user.is_super_admin or current_user:\n            self.schema = UserSchema\n        else:\n            self.schema = UserSchemaPublic\n\n    def before_get_object(self, view_kwargs):\n        \"\"\"\n        before get method for user object\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if view_kwargs.get('notification_id') is not None:\n            notification = safe_query(self, Notification, 'id', view_kwargs['notification_id'], 'notification_id')\n            if notification.user_id is not None:\n                view_kwargs['id'] = notification.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('feedback_id') is not None:\n            feedback = safe_query(self, Feedback, 'id', view_kwargs['feedback_id'], 'feedback_id')\n            if feedback.user_id is not None:\n                view_kwargs['id'] = feedback.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('attendee_id') is not None:\n            attendee = safe_query(self, TicketHolder, 'id', view_kwargs['attendee_id'], 'attendee_id')\n            if attendee.user is not None:\n                if (not has_access('is_user_itself',\n                                   user_id=attendee.user.id) or not has_access('is_coorganizer',\n                                                                               event_id=attendee.event_id)):\n                    raise ForbiddenException({'source': ''}, 'Access Forbidden')\n                view_kwargs['id'] = attendee.user.id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('event_invoice_id') is not None:\n            event_invoice = safe_query(self, EventInvoice, 'id', view_kwargs['event_invoice_id'], 'event_invoice_id')\n            if event_invoice.user_id is not None:\n                view_kwargs['id'] = event_invoice.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('users_events_role_id') is not None:\n            users_events_role = safe_query(self, UsersEventsRoles, 'id', view_kwargs['users_events_role_id'],\n                                           'users_events_role_id')\n            if users_events_role.user_id is not None:\n                view_kwargs['id'] = users_events_role.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('speaker_id') is not None:\n            speaker = safe_query(self, Speaker, 'id', view_kwargs['speaker_id'], 'speaker_id')\n            if speaker.user_id is not None:\n                view_kwargs['id'] = speaker.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('session_id') is not None:\n            session = safe_query(self, Session, 'id', view_kwargs['session_id'], 'session_id')\n            if session.creator_id is not None:\n                view_kwargs['id'] = session.creator_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('access_code_id') is not None:\n            access_code = safe_query(self, AccessCode, 'id', view_kwargs['access_code_id'], 'access_code_id')\n            if access_code.marketer_id is not None:\n                view_kwargs['id'] = access_code.marketer_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('discount_code_id') is not None:\n            discount_code = safe_query(self, DiscountCode, 'id', view_kwargs['discount_code_id'], 'discount_code_id')\n            if discount_code.marketer_id is not None:\n                view_kwargs['id'] = discount_code.marketer_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('email_notification_id') is not None:\n            email_notification = safe_query(self, EmailNotification, 'id', view_kwargs['email_notification_id'],\n                                            'email_notification_id')\n            if email_notification.user_id is not None:\n                view_kwargs['id'] = email_notification.user_id\n            else:\n                view_kwargs['id'] = None\n\n    def before_update_object(self, user, data, view_kwargs):\n        # TODO: Make a celery task for this\n        # if data.get('avatar_url') and data['original_image_url'] != user.original_image_url:\n        #     try:\n        #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)\n        #     except (urllib.error.HTTPError, urllib.error.URLError):\n        #         raise UnprocessableEntity(\n        #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'\n        #         )\n        #     data['original_image_url'] = uploaded_images['original_image_url']\n        #     data['small_image_url'] = uploaded_images['thumbnail_image_url']\n        #     data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url']\n        #     data['icon_image_url'] = uploaded_images['icon_image_url']\n        users_email = data.get('email', None)\n        if users_email is not None:\n            users_email = users_email.strip()\n\n        if has_access('is_admin') and data.get('deleted_at') != user.deleted_at:\n            user.deleted_at = data.get('deleted_at')\n\n        if users_email is not None and users_email != user.email:\n            try:\n                db.session.query(User).filter_by(email=users_email).one()\n            except NoResultFound:\n                view_kwargs['email_changed'] = user.email\n            else:\n                raise ConflictException({'pointer': '/data/attributes/email'}, \"Email already exists\")\n\n        if has_access('is_super_admin') and data.get('is_admin') and data.get('is_admin') != user.is_admin:\n            user.is_admin = not user.is_admin\n\n        if has_access('is_admin') and ('is_sales_admin' in data) and data.get('is_sales_admin') != user.is_sales_admin:\n            user.is_sales_admin = not user.is_sales_admin\n\n        if has_access('is_admin') and ('us_marketer' in data) and data.get('is_marketer') != user.is_marketer:\n            user.is_marketer = not user.is_marketer\n\n        if data.get('avatar_url'):\n            start_image_resizing_tasks(user, data['avatar_url'])\n\n    def after_update_object(self, user, data, view_kwargs):\n        \"\"\"\n        method to mail user about email change\n        :param user:\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if view_kwargs.get('email_changed'):\n            send_email_change_user_email(user, view_kwargs.get('email_changed'))\n\n    decorators = (api.has_permission('is_user_itself', fetch=\"user_id,id\", fetch_as=\"user_id\",\n                                     model=[Notification, Feedback, UsersEventsRoles, Session, EventInvoice, AccessCode,\n                                            DiscountCode, EmailNotification, Speaker, User],\n                                     fetch_key_url=\"notification_id, feedback_id, users_events_role_id, session_id, \\\n                  event_invoice_id, access_code_id, discount_code_id, email_notification_id, speaker_id, id\",\n                                     leave_if=lambda a: a.get('attendee_id')),)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User,\n                  'methods': {\n                      'before_get_object': before_get_object,\n                      'before_update_object': before_update_object,\n                      'after_update_object': after_update_object\n                  }}\n\n\nclass UserRelationship(ResourceRelationship):\n    \"\"\"\n    User Relationship\n    \"\"\"\n    decorators = (is_user_itself,)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User}\n\n\n@user_misc_routes.route('/users/checkEmail', methods=['POST'])\ndef is_email_available():\n    email = request.json.get('email', None)\n    if email:\n        if get_count(db.session.query(User).filter_by(email=email)):\n            return jsonify(\n                result=\"False\"\n            )\n        else:\n            return jsonify(\n                result=\"True\"\n            )\n    else:\n        abort(\n            make_response(jsonify(error=\"Email field missing\"), 422)\n        )\n\n\ndef start_image_resizing_tasks(user, original_image_url):\n    user_id = str(user.id)\n    from .helpers.tasks import resize_user_images_task\n    resize_user_images_task.delay(user_id, original_image_url)\n", "path": "app/api/users.py"}], "after_files": [{"content": "import base64\n\nfrom flask import Blueprint, request, jsonify, abort, make_response\nfrom flask_jwt import current_identity as current_user\nfrom flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship\nfrom sqlalchemy.orm.exc import NoResultFound\nimport urllib.error\n\nfrom app import get_settings\nfrom app.api.bootstrap import api\nfrom app.api.helpers.db import safe_query, get_count\nfrom app.api.helpers.exceptions import ConflictException, UnprocessableEntity, ForbiddenException\nfrom app.api.helpers.files import create_save_image_sizes, make_frontend_url\nfrom app.api.helpers.mail import send_email_confirmation, send_email_change_user_email, send_email_with_action\nfrom app.api.helpers.permission_manager import has_access\nfrom app.api.helpers.permissions import is_user_itself\nfrom app.api.helpers.utilities import get_serializer, str_generator\nfrom app.api.schema.users import UserSchema, UserSchemaPublic\nfrom app.models import db\nfrom app.models.access_code import AccessCode\nfrom app.models.discount_code import DiscountCode\nfrom app.models.email_notification import EmailNotification\nfrom app.models.event_invoice import EventInvoice\nfrom app.models.feedback import Feedback\nfrom app.models.mail import USER_REGISTER_WITH_PASSWORD, PASSWORD_RESET_AND_VERIFY\nfrom app.models.notification import Notification\nfrom app.models.session import Session\nfrom app.models.speaker import Speaker\nfrom app.models.ticket_holder import TicketHolder\nfrom app.models.user import User\nfrom app.models.users_events_role import UsersEventsRoles\n\nuser_misc_routes = Blueprint('user_misc', __name__, url_prefix='/v1')\n\n\nclass UserList(ResourceList):\n    \"\"\"\n    List and create Users\n    \"\"\"\n\n    def before_create_object(self, data, view_kwargs):\n        \"\"\"\n        method to check if there is an existing user with same email which is received in data to create a new user\n        and if the password is at least 8 characters long\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if len(data['password']) < 8:\n            raise UnprocessableEntity({'source': '/data/attributes/password'},\n                                       'Password should be at least 8 characters long')\n        if db.session.query(User.id).filter_by(email=data['email'].strip()).scalar() is not None:\n            raise ConflictException({'pointer': '/data/attributes/email'}, \"Email already exists\")\n\n    def after_create_object(self, user, data, view_kwargs):\n        \"\"\"\n        method to send-\n        email notification\n        mail link for register verification\n        add image urls\n        :param user:\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n\n        if user.was_registered_with_order:\n            link = make_frontend_url('/reset-password', {'token': user.reset_password})\n            send_email_with_action(user, PASSWORD_RESET_AND_VERIFY, app_name=get_settings()['app_name'],\n                                   email=user.email, link=link)\n        else:\n            s = get_serializer()\n            hash = str(base64.b64encode(str(s.dumps([user.email, str_generator()])).encode()), 'utf-8')\n            link = make_frontend_url('/verify'.format(id=user.id), {'token': hash})\n            send_email_with_action(user, USER_REGISTER_WITH_PASSWORD, app_name=get_settings()['app_name'],\n                                   email=user.email)\n            send_email_confirmation(user.email, link)\n        # TODO Handle in a celery task\n        # if data.get('original_image_url'):\n        #     try:\n        #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)\n        #     except (urllib.error.HTTPError, urllib.error.URLError):\n        #         raise UnprocessableEntity(\n        #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'\n        #         )\n        #     uploaded_images['small_image_url'] = uploaded_images['thumbnail_image_url']\n        #     del uploaded_images['large_image_url']\n        #     self.session.query(User).filter_by(id=user.id).update(uploaded_images)\n\n        if data.get('avatar_url'):\n            start_image_resizing_tasks(user, data['avatar_url'])\n\n    decorators = (api.has_permission('is_admin', methods=\"GET\"),)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User,\n                  'methods': {\n                      'before_create_object': before_create_object,\n                      'after_create_object': after_create_object\n                  }}\n\n\nclass UserDetail(ResourceDetail):\n    \"\"\"\n    User detail by id\n    \"\"\"\n\n    def before_get(self, args, kwargs):\n\n        if current_user.is_admin or current_user.is_super_admin or current_user:\n            self.schema = UserSchema\n        else:\n            self.schema = UserSchemaPublic\n\n    def before_get_object(self, view_kwargs):\n        \"\"\"\n        before get method for user object\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if view_kwargs.get('notification_id') is not None:\n            notification = safe_query(self, Notification, 'id', view_kwargs['notification_id'], 'notification_id')\n            if notification.user_id is not None:\n                view_kwargs['id'] = notification.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('feedback_id') is not None:\n            feedback = safe_query(self, Feedback, 'id', view_kwargs['feedback_id'], 'feedback_id')\n            if feedback.user_id is not None:\n                view_kwargs['id'] = feedback.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('attendee_id') is not None:\n            attendee = safe_query(self, TicketHolder, 'id', view_kwargs['attendee_id'], 'attendee_id')\n            if attendee.user is not None:\n                if (not has_access('is_user_itself',\n                                   user_id=attendee.user.id) or not has_access('is_coorganizer',\n                                                                               event_id=attendee.event_id)):\n                    raise ForbiddenException({'source': ''}, 'Access Forbidden')\n                view_kwargs['id'] = attendee.user.id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('event_invoice_id') is not None:\n            event_invoice = safe_query(self, EventInvoice, 'id', view_kwargs['event_invoice_id'], 'event_invoice_id')\n            if event_invoice.user_id is not None:\n                view_kwargs['id'] = event_invoice.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('users_events_role_id') is not None:\n            users_events_role = safe_query(self, UsersEventsRoles, 'id', view_kwargs['users_events_role_id'],\n                                           'users_events_role_id')\n            if users_events_role.user_id is not None:\n                view_kwargs['id'] = users_events_role.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('speaker_id') is not None:\n            speaker = safe_query(self, Speaker, 'id', view_kwargs['speaker_id'], 'speaker_id')\n            if speaker.user_id is not None:\n                view_kwargs['id'] = speaker.user_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('session_id') is not None:\n            session = safe_query(self, Session, 'id', view_kwargs['session_id'], 'session_id')\n            if session.creator_id is not None:\n                view_kwargs['id'] = session.creator_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('access_code_id') is not None:\n            access_code = safe_query(self, AccessCode, 'id', view_kwargs['access_code_id'], 'access_code_id')\n            if access_code.marketer_id is not None:\n                view_kwargs['id'] = access_code.marketer_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('discount_code_id') is not None:\n            discount_code = safe_query(self, DiscountCode, 'id', view_kwargs['discount_code_id'], 'discount_code_id')\n            if discount_code.marketer_id is not None:\n                view_kwargs['id'] = discount_code.marketer_id\n            else:\n                view_kwargs['id'] = None\n\n        if view_kwargs.get('email_notification_id') is not None:\n            email_notification = safe_query(self, EmailNotification, 'id', view_kwargs['email_notification_id'],\n                                            'email_notification_id')\n            if email_notification.user_id is not None:\n                view_kwargs['id'] = email_notification.user_id\n            else:\n                view_kwargs['id'] = None\n\n    def before_update_object(self, user, data, view_kwargs):\n        # TODO: Make a celery task for this\n        # if data.get('avatar_url') and data['original_image_url'] != user.original_image_url:\n        #     try:\n        #         uploaded_images = create_save_image_sizes(data['original_image_url'], 'speaker-image', user.id)\n        #     except (urllib.error.HTTPError, urllib.error.URLError):\n        #         raise UnprocessableEntity(\n        #             {'source': 'attributes/original-image-url'}, 'Invalid Image URL'\n        #         )\n        #     data['original_image_url'] = uploaded_images['original_image_url']\n        #     data['small_image_url'] = uploaded_images['thumbnail_image_url']\n        #     data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url']\n        #     data['icon_image_url'] = uploaded_images['icon_image_url']\n        users_email = data.get('email', None)\n        if users_email is not None:\n            users_email = users_email.strip()\n\n        if has_access('is_admin') and data.get('deleted_at') != user.deleted_at:\n            user.deleted_at = data.get('deleted_at')\n\n        if has_access('is_user_itself', user_id=user.id) and data.get('deleted_at') != user.deleted_at:\n            if len(user.events) != 0:\n                raise ForbiddenException({'source': ''}, \"Users associated with events cannot be deleted\")\n            elif len(user.orders) != 0:\n                raise ForbiddenException({'source': ''}, \"Users associated with orders cannot be deleted\")\n            else:\n                user.deleted_at = data.get('deleted_at')\n\n        if users_email is not None and users_email != user.email:\n            try:\n                db.session.query(User).filter_by(email=users_email).one()\n            except NoResultFound:\n                view_kwargs['email_changed'] = user.email\n            else:\n                raise ConflictException({'pointer': '/data/attributes/email'}, \"Email already exists\")\n\n        if has_access('is_super_admin') and data.get('is_admin') and data.get('is_admin') != user.is_admin:\n            user.is_admin = not user.is_admin\n\n        if has_access('is_admin') and ('is_sales_admin' in data) and data.get('is_sales_admin') != user.is_sales_admin:\n            user.is_sales_admin = not user.is_sales_admin\n\n        if has_access('is_admin') and ('us_marketer' in data) and data.get('is_marketer') != user.is_marketer:\n            user.is_marketer = not user.is_marketer\n\n        if data.get('avatar_url'):\n            start_image_resizing_tasks(user, data['avatar_url'])\n\n    def after_update_object(self, user, data, view_kwargs):\n        \"\"\"\n        method to mail user about email change\n        :param user:\n        :param data:\n        :param view_kwargs:\n        :return:\n        \"\"\"\n        if view_kwargs.get('email_changed'):\n            send_email_change_user_email(user, view_kwargs.get('email_changed'))\n\n    decorators = (api.has_permission('is_user_itself', fetch=\"user_id,id\", fetch_as=\"user_id\",\n                                     model=[Notification, Feedback, UsersEventsRoles, Session, EventInvoice, AccessCode,\n                                            DiscountCode, EmailNotification, Speaker, User],\n                                     fetch_key_url=\"notification_id, feedback_id, users_events_role_id, session_id, \\\n                  event_invoice_id, access_code_id, discount_code_id, email_notification_id, speaker_id, id\",\n                                     leave_if=lambda a: a.get('attendee_id')),)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User,\n                  'methods': {\n                      'before_get_object': before_get_object,\n                      'before_update_object': before_update_object,\n                      'after_update_object': after_update_object\n                  }}\n\n\nclass UserRelationship(ResourceRelationship):\n    \"\"\"\n    User Relationship\n    \"\"\"\n    decorators = (is_user_itself,)\n    schema = UserSchema\n    data_layer = {'session': db.session,\n                  'model': User}\n\n\n@user_misc_routes.route('/users/checkEmail', methods=['POST'])\ndef is_email_available():\n    email = request.json.get('email', None)\n    if email:\n        if get_count(db.session.query(User).filter_by(email=email)):\n            return jsonify(\n                result=\"False\"\n            )\n        else:\n            return jsonify(\n                result=\"True\"\n            )\n    else:\n        abort(\n            make_response(jsonify(error=\"Email field missing\"), 422)\n        )\n\n\ndef start_image_resizing_tasks(user, original_image_url):\n    user_id = str(user.id)\n    from .helpers.tasks import resize_user_images_task\n    resize_user_images_task.delay(user_id, original_image_url)\n", "path": "app/api/users.py"}]}