Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datanar 2.5.0 (dev) #49

Merged
merged 34 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ff45095
Merge pull request #47 from Gray-Advantage/dev
Gray-Advantage Jul 24, 2024
e70b7f1
feat: Add base templates for new API docs
Gray-Advantage Jul 26, 2024
c308947
style: black formation
Gray-Advantage Jul 26, 2024
b123ed9
fix: some format in README.md
Gray-Advantage Jul 28, 2024
2311d45
fix: add `makemigrations` before start django container
Gray-Advantage Aug 16, 2024
4ac111c
feat: add `Docker` and `Redis` to about page
Gray-Advantage Aug 16, 2024
5bae282
feat: Translating the repainting of the interface theme from JS to CSS
Gray-Advantage Aug 16, 2024
9041201
fix: deleting an unnecessary flag in .github\workflows
Gray-Advantage Aug 16, 2024
0d27b84
feat: Adding tracking of the method of creating the `Redirect` ip add…
Gray-Advantage Aug 16, 2024
512e7d0
feat: Redesigned user profile page + added thumbnails instead of real…
Gray-Advantage Aug 16, 2024
b6dc130
feat: preparation for new documentation
Gray-Advantage Aug 16, 2024
4bbd0e2
style: black + flake8
Gray-Advantage Aug 16, 2024
dc65af7
feat: add translation + Preamble API [1/7]
Gray-Advantage Aug 16, 2024
ab4c907
feat: add translation + Token API [3/7]
Gray-Advantage Aug 16, 2024
f136ced
fix: Fixing css rendering on chromium browsers + additional minificat…
Gray-Advantage Aug 16, 2024
b29f6f8
feat: add translation + Redirect API [4/7]
Gray-Advantage Aug 17, 2024
a50bcad
feat: Set which fields will be shown to the client when creating redi…
Gray-Advantage Aug 17, 2024
56db195
fix: color for .token.operator
Gray-Advantage Aug 17, 2024
f0a0802
fix: (!) don`t check blocked_domain if set custom_url
Gray-Advantage Aug 17, 2024
16e9f97
style: black
Gray-Advantage Aug 17, 2024
6145bf8
feat: add translation + Done API [7/7]
Gray-Advantage Aug 19, 2024
6a2709c
feat: add pagination to BlackList
Gray-Advantage Aug 19, 2024
6180354
fix: 404 err while delete last obj in page and redirect to this page
Gray-Advantage Aug 19, 2024
3f0660b
test: add test for api
Gray-Advantage Aug 19, 2024
976f1ca
test: add test for qr_codes
Gray-Advantage Aug 19, 2024
02574ef
style: black + flake8
Gray-Advantage Aug 19, 2024
c7c3166
test: add test for deactivation redirects
Gray-Advantage Aug 20, 2024
c8c89e1
feat: upgrade block domain system
Gray-Advantage Aug 20, 2024
677ae65
test: for new block domain system
Gray-Advantage Aug 20, 2024
9bed875
feat: add info about activate status in redirect detail
Gray-Advantage Aug 20, 2024
c3fe417
feat: update scheme in README.md
Gray-Advantage Aug 20, 2024
361710e
fix: celery cleaning in docker
Gray-Advantage Aug 20, 2024
ae3a5ed
feat: add auto block action to admin panel
Gray-Advantage Aug 20, 2024
68e89bf
feat: Datanar 2.5.0
Gray-Advantage Aug 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ jobs:
cd ~/datanar
git reset --hard origin/main
git pull origin main
docker compose down -v
docker compose down
docker compose up --build -d
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ RUN rm -rf requirements
COPY ./datanar /datanar/
WORKDIR /datanar

CMD python manage.py migrate \
CMD python manage.py makemigrations \
&& python manage.py migrate \
&& python manage.py init_superuser \
&& python manage.py compilemessages \
&& python manage.py collectstatic --no-input \
Expand Down
29 changes: 10 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# [Datanar](https://datanar.ru) - сайт по сокращению ссылок

---

## Содержание
- [Введение](#введение)
- [Полезность](#для-чего-может-быть-полезно-сокращать-ссылки)
Expand All @@ -16,8 +14,6 @@
- [Контейнеризация docker](#контейнеризация-docker)
- [Авторы](#авторы---эти-прекрасные-люди)

---

## Введение
[Datanar](https://datanar.ru) представляет собой сервис для сокращения ссылок,
который позволяет пользователям преобразовывать длинные URL-адреса в короткие
Expand Down Expand Up @@ -59,8 +55,6 @@
- Указывать сколько переходов можно совершить по ссылке
- Связать свой сервис с нашим по API

---

## Структура проекта
### Используемые фреймворки / библиотеки
- [Bootstrap](https://getbootstrap.com/) - популярная (html / css / js)
Expand All @@ -79,11 +73,11 @@
![scheme](docs/for_readme/scheme.png)

Основных моделей три - `Redirect`, `Click` и `BlockedDomain`
- `Redirect` - хранит в себе связь между длинной и короткой ссылкой
- `Redirect` - хранит в себе связь между длинным URL-адресом и короткой ссылкой
- `Click` - хранит информацию о переходе по `Redirect`
(Для статистики и для ограничения по количеству переходов)
- `BlockedDomain` - регулярное выражение, описывающие url-адреса, которые
запрещены для сокращения
(для введения статистики)
- `BlockedDomain` - регулярное выражение, описывающие URL-адреса, которые
запрещены для сокращения

### Контейнеры docker
Проект развёрнут с помощью технологии контейнеризации docker compose и имеет
Expand All @@ -101,9 +95,8 @@
- [Redis](https://hub.docker.com/_/redis) - быстрый сервер баз данных типа
ключ-значение. Требуется для celery
- [Celery](Dockerfile) - контейнер, созданный на базе `Django`, но с
изменённой командой запуска

---
изменённой командой запуска, является очередью задач для массового сокращения
ссылок и динамического отслеживания за сроком годности перенаправлений

## Развёртывание
Данная документация предлагает два основных способа запуска (развёртывания)
Expand All @@ -114,12 +107,10 @@
Долгий и трудный путь, зато вы имеете полный контроль над всем происходящим

### [Контейнеризация docker](docs/docker-install.md)
- подразумевает загрузку одной единственной программы и её настройку, а дальше
запуск всего приложения в полной комплектации с помощью одной команды.
Быстрый и простой путь, большая часть вопросов уже решена, остальное дело
техники

---
- подразумевает загрузку одной единственной программы Docker и её настройку,
а дальше запуск всего приложения в полной комплектации с помощью одной
команды. Быстрый и простой путь, большая часть вопросов уже решена, остальное
дело техники

## Авторы - эти прекрасные люди:
<div style="display: flex; align-items: center;">
Expand Down
108 changes: 103 additions & 5 deletions datanar/api/tests/test_correct_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from django.urls import reverse
from rest_framework import status

from redirects.models import Redirect


class ApiCorrectTest(TestCase):
fixtures = ["fixtures/for_test_data.json"]
Expand All @@ -19,8 +21,28 @@ def setUp(self):
"short_EEE",
"short_FFF",
]

def test_new_token_context(self):
self.full_redirect_fields = {
"id",
"long_link",
"short_link",
"password",
"validity_days",
"validity_clicks",
"created_at",
"create_method",
"is_active",
"deactivated_at",
}
self.simple_redirect_fields = {
"long_link",
"short_link",
"password",
"validity_days",
"validity_clicks",
"created_at",
}

def test_create_new_token_context(self):
client = Client()

response1 = client.post(
Expand All @@ -40,7 +62,7 @@ def test_new_token_context(self):
response2.json()["token"],
)

def test_token_context(self):
def test_get_token_context(self):
response1 = Client().post(
reverse("api:get_token"),
data={"username": self.username, "password": self.password},
Expand All @@ -55,7 +77,7 @@ def test_token_context(self):

self.assertEqual(response1.json()["token"], response2.json()["token"])

def test_redirects_list(self):
def test_get_redirects_list(self):
response = self.client.get(reverse("api:redirect-list"))
self.assertEqual(response.status_code, status.HTTP_200_OK)

Expand All @@ -64,8 +86,19 @@ def test_redirects_list(self):
self.short_links,
)

def test_get_redirects_list_context(self):
response = self.client.get(reverse("api:redirect-list"))
self.assertEqual(response.status_code, status.HTTP_200_OK)

for redirect in response.json():
self.assertEqual(
redirect.keys(),
self.full_redirect_fields,
"Отсутствует обязательное для авторизированного клиента поле",
)

def test_redirect_id(self):
for i in range(1, 7):
for i in range(1, len(self.short_links) + 1):
response = self.client.get(
reverse("api:redirect-detail", args=[i]),
)
Expand All @@ -75,14 +108,40 @@ def test_redirect_id(self):
self.short_links[i - 1],
)

def test_redirect_id_context(self):
for i in range(1, len(self.short_links) + 1):
response = self.client.get(
reverse("api:redirect-detail", args=[i]),
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.json().keys(),
self.full_redirect_fields,
"Отсутствует обязательное для авторизированного клиента поле",
)

def test_create_redirect(self):
redirect_count = Redirect.objects.count()

response = self.client.post(
reverse("api:redirect-list"),
data={"long_link": "https://python.org/"},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.json()["long_link"], "https://python.org/")

self.assertEqual(
Redirect.objects.count(),
redirect_count + 1,
"Redirect не создан",
)

self.assertEqual(
Redirect.objects.last().create_method,
Redirect.CreateMethod.API,
"Метод создания для `redirect` неправильный",
)

response = self.client.get(
reverse(
"redirects:redirect",
Expand All @@ -92,6 +151,37 @@ def test_create_redirect(self):
)
self.assertRedirects(response, "https://python.org/")

def test_create_redirect_context(self):
response = Client().post(
reverse("api:redirect-list"),
data={"long_link": "https://python.org/"},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
response.json().keys(),
self.simple_redirect_fields,
"Присутствуют лишние поля для не авторизированного пользователя",
)

token = (
Client()
.post(
reverse("api:get_token"),
data={"username": self.username, "password": self.password},
)
.json()["token"]
)
response = self.client.post(
reverse("api:redirect-list"),
data={"token": token, "long_link": "https://python.org/"},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
response.json().keys(),
self.full_redirect_fields,
"Отсутствует обязательное для авторизированного пользователя поле",
)

def test_create_redirect_with_short_link(self):
response = self.client.post(
reverse("api:redirect-list"),
Expand All @@ -105,8 +195,16 @@ def test_create_redirect_with_short_link(self):
self.assertEqual(response.json()["short_link"], "test_short")

def test_delete_redirect(self):
redirect_count = Redirect.objects.count()

response = self.client.delete(reverse("api:redirect-detail", args=[1]))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

self.assertEqual(
Redirect.objects.count(),
redirect_count - 1,
"Redirect не удалён",
)


__all__ = []
12 changes: 12 additions & 0 deletions datanar/api/tests/test_wrong_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ def test_redirect_without_auth(self):
response = Client().get(reverse("api:redirect-detail", args=[1]))
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_redirect_with_wrong_token(self):
token = self.client.post(
reverse("api:get_token"),
data={"username": self.username, "password": self.password},
).json()["token"]

response = Client().get(
reverse("api:redirect-detail", args=[1]),
data={"token": token + "_w"},
)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

def test_redirect_with_wrong_id(self):
response = self.client.get(reverse("api:redirect-detail", args=[42]))
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
Expand Down
32 changes: 31 additions & 1 deletion datanar/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,43 @@ def __init__(self):
router.register("redirects", views.RedirectViewSet, basename="redirect")

urlpatterns = [
path("docs/", views.APIDocumentationView.as_view(), name="api_docs"),
path("docs/", views.APIDocsPreambleView.as_view(), name="docs_preamble"),
path("api-token-auth/", rest_views.obtain_auth_token, name="get_token"),
path(
"api-token-auth-update/",
views.CreateNewTokenView.as_view(),
name="create_new_token",
),
path(
"docs/qr_code_get",
views.APIDocsQRCodeGetView.as_view(),
name="docs_qr_code_get",
),
path(
"docs/redirect_get",
views.APIDocsRedirectGetView.as_view(),
name="docs_redirect_get",
),
path(
"docs/redirect_create",
views.APIDocsRedirectCreateView.as_view(),
name="docs_redirect_create",
),
path(
"docs/redirect_delete",
views.APIDocsRedirectDeleteView.as_view(),
name="docs_redirect_delete",
),
path(
"docs/token_get",
views.APIDocsTokenGetView.as_view(),
name="docs_token_get",
),
path(
"docs/token_create",
views.APIDocsTokenCreateView.as_view(),
name="docs_token_create",
),
*router.urls,
]

Expand Down
Loading
Loading