Skip to content

Commit 086d321

Browse files
authored
Added the ability to hide button (#60)
1 parent 0aef30e commit 086d321

6 files changed

Lines changed: 133 additions & 11 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""#56_add_is_hidden_field
2+
3+
Revision ID: 52230bfc3f86
4+
Revises: 1bb798899506
5+
Create Date: 2024-07-29 20:05:34.777852
6+
7+
"""
8+
9+
import sqlalchemy as sa
10+
from alembic import op
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '52230bfc3f86'
15+
down_revision = '1bb798899506'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column('button', sa.Column('is_hidden', sa.Boolean(), nullable=False))
23+
# ### end Alembic commands ###
24+
25+
26+
def downgrade():
27+
# ### commands auto generated by Alembic - please adjust! ###
28+
op.drop_column('button', 'is_hidden')
29+
# ### end Alembic commands ###

services_backend/models/database.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class Button(Base):
6363
icon: Mapped[str] = mapped_column(String)
6464
link: Mapped[str] = mapped_column(String)
6565
type: Mapped[Type] = mapped_column(DbEnum(Type, native_enum=False), nullable=False)
66+
is_hidden: Mapped[bool] = mapped_column(Boolean, default=False)
6667

6768
_scopes: Mapped[list[Scope]] = relationship("Scope", back_populates="button", lazy='joined', cascade='delete')
6869

services_backend/routes/button.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ class ButtonCreate(Base):
2222
name: str = Field(description='Название кнопки')
2323
link: str = Field(description='Ссылка, на которую перенаправляет кнопка')
2424
type: Type = Field(description='Тип открываемой ссылки (Ссылка приложения/Браузер в приложении/Браузер')
25-
required_scopes: set[str] | None = Field(description='Каким скоупы нужны, чтобы кнопка была доступна', default=None)
26-
optional_scopes: set[str] | None = Field(description='Каким скоупы желательны', default=None)
25+
is_hidden: bool = Field(description='Спрятана ли кнопка от пользователя', default=False)
26+
required_scopes: set[str] | None = Field(description='Какие скоупы нужны, чтобы кнопка была доступна', default=None)
27+
optional_scopes: set[str] | None = Field(description='Какиеп скоупы желательны', default=None)
2728

2829

2930
class ButtonUpdate(Base):
@@ -35,13 +36,15 @@ class ButtonUpdate(Base):
3536
type: Type | None = Field(
3637
description='Тип открываемой ссылки (Ссылка приложения/Браузер в приложении/Браузер', default=None
3738
)
38-
required_scopes: set[str] | None = Field(description='Каким скоупы нужны, чтобы кнопка была доступна', default=None)
39-
optional_scopes: set[str] | None = Field(description='Каким скоупы желательны', default=None)
39+
is_hidden: bool | None = Field(description='Спрятана ли кнопка от пользователя', default=None)
40+
required_scopes: set[str] | None = Field(description='Какие скоупы нужны, чтобы кнопка была доступна', default=None)
41+
optional_scopes: set[str] | None = Field(description='Какие скоупы желательны', default=None)
4042

4143

4244
class ButtonView(Enum):
4345
ACTIVE = "active"
4446
BLOCKED = "blocked"
47+
HIDDEN = "hidden"
4548

4649

4750
class ButtonGet(Base):
@@ -120,7 +123,9 @@ def get_buttons(
120123
for button in category.buttons:
121124
view = ButtonView.ACTIVE
122125
scopes = set()
123-
if button.required_scopes - user_scopes:
126+
if button.is_hidden:
127+
view = ButtonView.HIDDEN
128+
elif button.required_scopes - user_scopes:
124129
view = ButtonView.BLOCKED
125130
else:
126131
scopes |= button.required_scopes
@@ -169,7 +174,9 @@ def get_button(
169174
raise HTTPException(status_code=404, detail="Button is not this category")
170175
view = ButtonView.ACTIVE
171176
scopes = set()
172-
if button.required_scopes - user_scopes:
177+
if button.is_hidden:
178+
view = ButtonView.HIDDEN
179+
elif button.required_scopes - user_scopes:
173180
view = ButtonView.BLOCKED
174181
else:
175182
scopes |= button.required_scopes
@@ -297,7 +304,9 @@ def get_service(
297304
raise HTTPException(status_code=404, detail="Button does not exist")
298305
view = ButtonView.ACTIVE
299306
scopes = set()
300-
if button.required_scopes - user_scopes:
307+
if button.is_hidden:
308+
view = ButtonView.HIDDEN
309+
elif button.required_scopes - user_scopes:
301310
view = ButtonView.BLOCKED
302311
else:
303312
scopes |= button.required_scopes

services_backend/routes/category.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from fastapi_sqlalchemy import db
77
from pydantic import Field, conint
88

9-
from services_backend.models.database import Button, Category, Type
9+
from services_backend.models.database import Button, Category
1010
from services_backend.schemas import Base
1111

1212
from .button import ButtonGet, ButtonView
@@ -109,7 +109,9 @@ def get_categories(
109109
for button in row.buttons:
110110
view = ButtonView.ACTIVE
111111
scopes = set()
112-
if button.required_scopes - user_scopes:
112+
if button.is_hidden:
113+
view = ButtonView.HIDDEN
114+
elif button.required_scopes - user_scopes:
113115
view = ButtonView.BLOCKED
114116
else:
115117
scopes |= button.required_scopes
@@ -119,7 +121,7 @@ def get_categories(
119121
"id": button.id,
120122
"icon": button.icon,
121123
"name": button.name,
122-
"link": (button.link if view == ButtonView.ACTIVE else None),
124+
"link": button.link if view == ButtonView.ACTIVE else None,
123125
"order": button.order,
124126
"type": button.type,
125127
"view": view.value,

tests/api/button.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,66 @@ def test_type_not_enum(client, dbsession, db_category):
235235
}
236236
res = client.post(f"/category/{db_category.id}/button", data=json.dumps(body))
237237
assert res.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
238+
239+
240+
def test_post_hidden_success(client, dbsession, db_category):
241+
body = {"icon": "qq", "name": "new", "link": "google.com", "type": "inapp", "is_hidden": True}
242+
res = client.post(f"/category/{db_category.id}/button", data=json.dumps(body))
243+
assert res.status_code == status.HTTP_200_OK
244+
res_body = res.json()
245+
assert res_body["icon"] == body["icon"]
246+
assert res_body["order"] == 1
247+
assert res_body["name"] == body["name"]
248+
assert res_body["link"] == body["link"]
249+
assert res_body["type"] == body["type"]
250+
db_button_created: Button = dbsession.query(Button).filter(Button.id == res_body["id"]).one_or_none()
251+
assert db_button_created
252+
assert db_button_created.icon == body["icon"]
253+
assert db_button_created.name == body["name"]
254+
assert db_button_created.category == db_category
255+
assert db_button_created.link == body["link"]
256+
assert db_button_created.type == body["type"]
257+
assert db_button_created.order == 1
258+
assert db_button_created.is_hidden == True
259+
dbsession.delete(db_button_created)
260+
dbsession.commit()
261+
262+
263+
def test_get_hidden_by_id_success(client, dbsession, db_button, db_category):
264+
db_button.is_hidden = True
265+
dbsession.commit()
266+
res = client.get(f"/category/{db_category.id}/button/{db_button.id}")
267+
assert res.status_code == status.HTTP_200_OK
268+
res_body = res.json()
269+
assert res_body['icon'] == db_button.icon
270+
assert res_body['name'] == db_button.name
271+
assert res_body['order'] == db_button.order
272+
assert res_body['link'] is None
273+
assert res_body['type'] == db_button.type
274+
assert res_body['view'] == "hidden"
275+
276+
277+
def test_patch_to_hide_success(client, db_button, db_category):
278+
body = {"is_hidden": True}
279+
res = client.patch(f"/category/{db_category.id}/button/{db_button.id}", data=json.dumps(body))
280+
assert res.status_code == status.HTTP_200_OK
281+
res_body = res.json()
282+
assert res_body["icon"] == db_button.icon
283+
assert res_body["order"] == db_button.order
284+
assert res_body["name"] == db_button.name
285+
assert res_body["link"] == db_button.link
286+
assert res_body["type"] == db_button.type
287+
assert res_body["is_hidden"] == True
288+
res = client.get(f"/category/{db_category.id}/button/{db_button.id}")
289+
assert res.status_code == status.HTTP_200_OK
290+
assert res.json()["link"] is None
291+
assert res.json()["view"] == "hidden"
292+
293+
294+
def test_delete_hidden_success(client, dbsession, db_button, db_category):
295+
db_button.is_hidden = True
296+
dbsession.commit()
297+
res = client.delete(f"/category/{db_category.id}/button/{db_button.id}")
298+
assert res.status_code == status.HTTP_200_OK
299+
q = dbsession.query(Button).filter(Button.id == db_button.id)
300+
assert not q.one_or_none()

tests/api/category.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,10 @@ def test_delete_order(db_category, client):
187187

188188
res = client.get(f"/category/{res1.json()['id']}")
189189
assert res.json()['order'] == 1
190+
client.delete(f"/category/{res1.json()['id']}")
190191

191192

192-
def test_scopes(client, mocker: MockerFixture):
193+
def test_scopes(client, dbsession, mocker: MockerFixture):
193194
user_mock = mocker.patch('auth_lib.fastapi.UnionAuth.__call__')
194195
user_mock.return_value = {
195196
"session_scopes": [{"id": 0, "name": "string", "comment": "string"}],
@@ -238,3 +239,20 @@ def test_scopes(client, mocker: MockerFixture):
238239

239240
res8 = client.get(f'/category/{id_}')
240241
assert res8.status_code == status.HTTP_404_NOT_FOUND
242+
243+
category = dbsession.query(Category).filter(Category.id == id_).one_or_none()
244+
dbsession.delete(category)
245+
dbsession.commit()
246+
247+
248+
def test_get_hidden_button_success(client, dbsession, db_button):
249+
db_button.is_hidden = True
250+
dbsession.commit()
251+
res = client.get('/category', params={"info": "buttons"})
252+
assert res.status_code == status.HTTP_200_OK
253+
res_body = res.json()
254+
assert len(res_body) == 1
255+
assert len(res_body[0]["buttons"]) == 1
256+
assert res_body[0]["buttons"][0]["id"] == db_button.id
257+
assert res_body[0]["buttons"][0]["view"] == "hidden"
258+
assert "link" not in res_body[0]["buttons"][0]

0 commit comments

Comments
 (0)