Skip to content

Commit

Permalink
Merge pull request #125 from Remmeauth/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
anastasiia-bilova authored Sep 12, 2019
2 parents c22f0c6 + a8ead22 commit c808c4c
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 16 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,31 @@ $ curl -X POST http://localhost:8000/block-producers/2/ \
| - | General execution | User with specified e-mail address does not exist. | 400 |
| - | General execution | Block producer with specified identifier does not exist. | 400 |

* `DELETE | /block-producers/{block_producer_identifier}/` - delete block producer by its identifier.

##### Request parameters

| Arguments | Type | Required | Description |
| :-----------------------: | :-----: | :------: | ----------------------------- |
| block_producer_identifier | Integer | Yes | Identifier of block producer. |

```bash
$ curl -X DELETE -H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0e....eyJ1c2VyX2....sOx4S9zpC..." \
http://localhost:8000/block-producers/2/ | python -m json.tool
{
"result": "Block producer has been deleted."
}
```

##### Known errors

| Argument | Level | Error message | Status code |
| :-----------------------: | :------------------------: | ---------------------------------------------------------------------- | :---------: |
| block_producer_identifier | Input arguments validation | Block producer with specified identifier does not exist. | 400 |
| username | Input arguments validation | User has no authority to delete this block producer by its identifier. | 400 |


* `GET | /block-producers/search/?phrase=block%20producer%20usa` - search block producers by phrase.

##### Request parameters
Expand Down
25 changes: 25 additions & 0 deletions directory/block_producer/domain/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,28 @@ def do(self):
Get block producers' likes number.
"""
return self.block_producer_like.get_numbers()


class DeleteBlockProducer:
"""
Delete block producer implementation.
"""

def __init__(self, user, block_producer):
"""
Constructor.
"""
self.user = user
self.block_producer = block_producer

def do(self, user_email, block_producer_id):
"""
Delete block producer by its identifier.
"""
if not self.user.does_exist_by_email(email=user_email):
raise UserWithSpecifiedEmailAddressDoesNotExistError

if not self.block_producer.does_exist(identifier=block_producer_id):
raise BlockProducerWithSpecifiedIdentifierDoesNotExistError

return self.block_producer.delete_(identifier=block_producer_id)
4 changes: 4 additions & 0 deletions directory/block_producer/fixtures/block_producer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"full_description": "# About Us\n\nFounded by a team of serial tech entrepreneurs, block producer Canada is headquartered in Montreal, Canada and is backed by reputable Canadian financial players. We believe that BP.IO will fundamentally change our economic and social systems and as such we are deeply committed to contribute to the growth of the ecosystem.",
"logo_url": "https://block-producers-directory.s3-us-west-2.amazonaws.com/bps/logos/default-block-producer-logotype.png",
"status": "active",
"created_at": "2019-06-01T13:19:37+00:00",
"linkedin_url": "https://www.linkedin.com/in/bpcanada",
"twitter_url": "https://twitter.com/bpcanada",
"medium_url": "https://medium.com/@bpcanada",
Expand All @@ -35,6 +36,7 @@
"full_description": "# About Us\n\nFounded by a team of serial tech entrepreneurs, block producer Canada is headquartered in Montreal, Canada and is backed by reputable Canadian financial players. We believe that BP.IO will fundamentally change our economic and social systems and as such we are deeply committed to contribute to the growth of the ecosystem.",
"logo_url": "https://block-producers-directory.s3-us-west-2.amazonaws.com/bps/logos/default-block-producer-logotype.png",
"status": "active",
"created_at": "2019-06-02T13:19:37+00:00",
"linkedin_url": "https://www.linkedin.com/in/bpcanada",
"twitter_url": "https://twitter.com/bpcanada",
"medium_url": "https://medium.com/@bpcanada",
Expand All @@ -59,6 +61,7 @@
"full_description": "# About Us\n\nFounded by a team of serial tech entrepreneurs, block producer USA is headquartered in San Francisco, USA and is backed by reputable American financial players. We believe that BP.IO will fundamentally change our economic and social systems and as such we are deeply committed to contribute to the growth of the ecosystem.",
"logo_url": "https://block-producers-directory.s3-us-west-2.amazonaws.com/bps/logos/default-block-producer-logotype.png",
"status": "active",
"created_at": "2019-06-03T13:19:37+00:00",
"linkedin_url": "https://www.linkedin.com/in/bpusa",
"twitter_url": "https://twitter.com/bpusa",
"medium_url": "https://medium.com/@bpusa",
Expand All @@ -83,6 +86,7 @@
"full_description": "# About Us\n\nFounded by a team of serial tech entrepreneurs, block producer Canada is headquartered in Montreal, Canada and is backed by reputable Canadian financial players. We believe that BP.IO will fundamentally change our economic and social systems and as such we are deeply committed to contribute to the growth of the ecosystem.",
"logo_url": "https://block-producers-directory.s3-us-west-2.amazonaws.com/bps/logos/default-block-producer-logotype.png",
"status": "active",
"created_at": "2019-06-04T13:19:37+00:00",
"linkedin_url": "https://www.linkedin.com/in/bpcanada",
"twitter_url": "https://twitter.com/bpcanada",
"medium_url": "https://medium.com/@bpcanada",
Expand Down
19 changes: 19 additions & 0 deletions directory/block_producer/migrations/0006_add_created_at.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-09-12 10:27

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('block_producer', '0005_add_status_field'),
]

operations = [
migrations.AddField(
model_name='blockproducer',
name='created_at',
field=models.DateTimeField(auto_now_add=True),
preserve_default=False,
),
]
17 changes: 15 additions & 2 deletions directory/block_producer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class BlockProducer(models.Model):
short_description = models.CharField(max_length=100, blank=False)
full_description = models.TextField(blank=True)
logo_url = models.URLField(max_length=200, blank=True, default=settings.DEFAULT_BLOCK_PRODUCER_LOGOTYPE_URL)

status = models.CharField(max_length=10, choices=BLOCK_PRODUCER_STATUSES, default=BLOCK_PRODUCER_STATUS_MODERATION)
created_at = models.DateTimeField(auto_now_add=True)

linkedin_url = models.URLField(max_length=200, blank=True)
twitter_url = models.URLField(max_length=200, blank=True)
Expand Down Expand Up @@ -81,7 +83,7 @@ def get_all(cls):
"""
Get block producers.
"""
block_producers_as_dicts = cls.objects.all().values()
block_producers_as_dicts = cls.objects.all().order_by('-created_at').values()

for block_producer in block_producers_as_dicts:

Expand All @@ -92,6 +94,7 @@ def get_all(cls):
del user_as_dict['created']

block_producer['user'] = user_as_dict
del block_producer['created_at']

return BlockProducerDto.schema().load(block_producers_as_dicts, many=True)

Expand Down Expand Up @@ -129,6 +132,7 @@ def get(cls, identifier):
del user_as_dict['created']

block_producer_as_dict['user'] = user_as_dict
del block_producer_as_dict['created_at']

return BlockProducerDto(**block_producer_as_dict)

Expand All @@ -144,7 +148,7 @@ def search(cls, phrase):

block_producers_as_list = cls.objects.annotate(
search=search_vector,
).filter(search=SearchQuery(phrase)).values()
).filter(search=SearchQuery(phrase)).order_by('-created_at').values()

for block_producer_as_dict in block_producers_as_list:
user_identifier = block_producer_as_dict.get('user_id')
Expand All @@ -155,6 +159,7 @@ def search(cls, phrase):
del user_as_dict['created']

del block_producer_as_dict['search']
del block_producer_as_dict['created_at']

block_producer_as_dict['user'] = user_as_dict

Expand All @@ -179,9 +184,17 @@ def get_last(cls, username):
del user_as_dict['created']

last_block_producer['user'] = user_as_dict
del last_block_producer['created_at']

return BlockProducerDto(**last_block_producer)

@classmethod
def delete_(cls, identifier):
"""
Delete block producer by its identifier.
"""
cls.objects.filter(id=identifier).delete()


class BlockProducerLike(models.Model):
"""
Expand Down
87 changes: 79 additions & 8 deletions directory/block_producer/tests/views/test_block_producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ def setUp(self):

self.user_token = response.data.get('token')

self.second_user = User.objects.create_user(
id=2,
email='john.cap@gmail.com',
username='john.cap',
password='john.cap.1337',
)

BlockProducer.objects.create(
id=4,
user=self.second_user,
name='Remme',
website_url='https://remmebp.com',
short_description='Founded by a team of serial tech entrepreneurs in Ukraine.',
)

def test_get_block_producer(self):
"""
Case: get block producer.
Expand Down Expand Up @@ -179,6 +194,62 @@ def test_update_block_producer_by_non_exiting_identifier(self):
assert expected_result == response.json()
assert HTTPStatus.NOT_FOUND == response.status_code

def test_delete_block_producer(self):
"""
Case: delete block producer by its identifier.
Expect: block producer deleted from the database.
"""
expected_result = {
'result': 'Block producer has been deleted.',
}

response = self.client.delete(
f'/block-producers/1/',
HTTP_AUTHORIZATION='JWT ' + self.user_token,
content_type='application/json',
)

assert expected_result == response.json()
assert HTTPStatus.OK == response.status_code

def test_delete_block_producer_by_non_exiting_identifier(self):
"""
Case: delete block producer by non-exiting identifier.
Expect: block producer with specified identifier does not exist error message.
"""
expected_result = {
'error': 'Block producer with specified identifier does not exist.',
}

non_existing_block_producer_identifier = 100500

response = self.client.delete(
f'/block-producers/{non_existing_block_producer_identifier}/',
HTTP_AUTHORIZATION='JWT ' + self.user_token,
content_type='application/json',
)

assert expected_result == response.json()
assert HTTPStatus.NOT_FOUND == response.status_code

def test_delete_block_producer_without_deletion_rights(self):
"""
Case: deleting a block producer without deletion rights.
Expect: user has no authority to delete this block producer by its identifier error message.
"""
expected_result = {
'error': 'User has no authority to delete this block producer by its identifier.',
}

response = self.client.delete(
f'/block-producers/4/',
HTTP_AUTHORIZATION='JWT ' + self.user_token,
content_type='application/json',
)

assert expected_result == response.json()
assert HTTPStatus.BAD_REQUEST == response.status_code


class TestBlockProducerCollection(TestCase):
"""
Expand Down Expand Up @@ -224,12 +295,12 @@ def test_get_block_producers(self):
expected_result = {
'result': [
{
'website_url': 'https://bpcanada.com',
'website_url': 'https://bpunitedkingdom.com',
'medium_url': '',
'facebook_url': '',
'name': 'Block producer Canada',
'name': 'Block producer United Kingdom',
'twitter_url': '',
'short_description': 'Founded by a team of serial tech entrepreneurs in Canada.',
'short_description': 'Founded by a team of serial tech entrepreneurs in United Kingdom.',
'full_description': '',
'github_url': '',
'telegram_url': '',
Expand All @@ -238,7 +309,7 @@ def test_get_block_producers(self):
'user_id': 3,
'reddit_url': '',
'location': '',
'id': 6,
'id': 7,
'linkedin_url': '',
'steemit_url': '',
'logo_url': 'https://block-producers-directory.s3-us-west-2.amazonaws.com/'
Expand All @@ -255,12 +326,12 @@ def test_get_block_producers(self):
},
},
{
'website_url': 'https://bpunitedkingdom.com',
'website_url': 'https://bpcanada.com',
'medium_url': '',
'facebook_url': '',
'name': 'Block producer United Kingdom',
'name': 'Block producer Canada',
'twitter_url': '',
'short_description': 'Founded by a team of serial tech entrepreneurs in United Kingdom.',
'short_description': 'Founded by a team of serial tech entrepreneurs in Canada.',
'full_description': '',
'github_url': '',
'telegram_url': '',
Expand All @@ -269,7 +340,7 @@ def test_get_block_producers(self):
'user_id': 3,
'reddit_url': '',
'location': '',
'id': 7,
'id': 6,
'linkedin_url': '',
'steemit_url': '',
'logo_url': 'https://block-producers-directory.s3-us-west-2.amazonaws.com/'
Expand Down
44 changes: 43 additions & 1 deletion directory/block_producer/views/block_producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
)
from block_producer.domain.objects import (
CreateBlockProducer,
DeleteBlockProducer,
GetBlockProducer,
GetBlockProducers,
GetUserLastBlockProducer,
Expand All @@ -32,7 +33,10 @@
)
from block_producer.models import BlockProducer
from services.telegram import TelegramBot
from user.domain.errors import UserWithSpecifiedEmailAddressDoesNotExistError
from user.domain.errors import (
UserHasNoAuthorityToDeleteThisBlockProducerError,
UserWithSpecifiedEmailAddressDoesNotExistError,
)
from user.models import User


Expand Down Expand Up @@ -92,6 +96,44 @@ def post(self, request, block_producer_id):

return JsonResponse({'result': 'Block producer has been updated.'}, status=HTTPStatus.OK)

@authentication_classes((JSONWebTokenAuthentication,))
def delete(self, request, block_producer_id):
"""
Delete block producer.
"""
user_email = request.user.email

try:
response = self.get(request=None, block_producer_id=block_producer_id)

json_response = json.loads(response.content)
username = json_response.get('result').get('user').get('username')

except BlockProducerWithSpecifiedIdentifierDoesNotExistError as error:
return JsonResponse({'error': error.message}, status=HTTPStatus.NOT_FOUND)

except AttributeError:
return JsonResponse(
{'error': BlockProducerWithSpecifiedIdentifierDoesNotExistError().message}, status=HTTPStatus.NOT_FOUND,
)

if username != request.user.username:
return JsonResponse(
{'error': UserHasNoAuthorityToDeleteThisBlockProducerError().message}, status=HTTPStatus.BAD_REQUEST,
)

try:
DeleteBlockProducer(user=self.user, block_producer=self.block_producer).do(
user_email=user_email, block_producer_id=block_producer_id,
)
except (
BlockProducerWithSpecifiedIdentifierDoesNotExistError,
UserWithSpecifiedEmailAddressDoesNotExistError,
) as error:
return JsonResponse({'error': error.message}, status=HTTPStatus.NOT_FOUND)

return JsonResponse({'result': 'Block producer has been deleted.'}, status=HTTPStatus.OK)


class BlockProducerCollection(APIView):
"""
Expand Down
12 changes: 12 additions & 0 deletions directory/user/domain/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,15 @@ def __init__(self):
Constructor.
"""
self.message = 'User has no authority to change password for this user by specified username.'


class UserHasNoAuthorityToDeleteThisBlockProducerError(Exception):
"""
User has no authority to delete this block producer by its identifier error.
"""

def __init__(self):
"""
Constructor.
"""
self.message = 'User has no authority to delete this block producer by its identifier.'
Loading

0 comments on commit c808c4c

Please sign in to comment.