Skip to content

Commit

Permalink
Merge pull request #15 from bernardito-luis/switches_full_info
Browse files Browse the repository at this point in the history
Switches full info
  • Loading branch information
kazauwa authored Nov 18, 2020
2 parents f5d8ebd + 7bdd33d commit f6cba09
Show file tree
Hide file tree
Showing 12 changed files with 318 additions and 16 deletions.
10 changes: 8 additions & 2 deletions its_on/admin/schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,23 @@ def deserialize(

class BaseSwitchAdminPostRequestSchema(Schema):
is_active = fields.Boolean()
groups = SplitList(fields.Str())
version = fields.Int()
comment = fields.Str()


class SwitchDetailAdminPostRequestSchema(BaseSwitchAdminPostRequestSchema):
pass
groups = SplitList(fields.Str())


class SwitchAddAdminPostRequestSchema(BaseSwitchAdminPostRequestSchema):
name = fields.Str()
groups = SplitList(fields.Str())


class SwitchAddFromAnotherItsOnAdminPostRequestSchema(BaseSwitchAdminPostRequestSchema):
name = fields.Str()
groups = fields.List(fields.Str())
is_hidden = fields.Boolean()


class UserDetailPostRequestSchema(Schema):
Expand Down
58 changes: 54 additions & 4 deletions its_on/admin/views/switches.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
from typing import Dict, List, Optional, Any
from typing import Dict, List, Optional, Union, Any

from aiopg.sa.result import RowProxy
import aiohttp_jinja2
from aiohttp import web
from aiohttp import ClientSession
from auth.decorators import login_required
from dynaconf import settings
from its_on.models import switches
from marshmallow.exceptions import ValidationError
import psycopg2
from sqlalchemy.sql import false, Select
from multidict import MultiDictProxy

from its_on.admin.mixins import GetObjectMixin, CreateMixin, UpdateMixin
from its_on.admin.schemes import SwitchDetailAdminPostRequestSchema, SwitchAddAdminPostRequestSchema
from its_on.admin.schemes import (
SwitchDetailAdminPostRequestSchema, SwitchAddAdminPostRequestSchema,
SwitchAddFromAnotherItsOnAdminPostRequestSchema,
)
from its_on.admin.permissions import CanEditSwitch


Expand All @@ -20,9 +25,12 @@ class SwitchListAdminView(web.View):

@aiohttp_jinja2.template('switches/index.html')
@login_required
async def get(self) -> Dict[str, Optional[List[RowProxy]]]:
async def get(self) -> Dict[str, Union[Optional[List[RowProxy]], bool]]:
flags = await self.get_response_data()
return {'flags': flags}
return {
'flags': flags,
'show_copy_button': bool(settings.SYNC_FROM_ITS_ON_URL),
}

async def get_response_data(self) -> List[RowProxy]:
objects = await self.load_objects()
Expand Down Expand Up @@ -140,6 +148,48 @@ async def post(self) -> Dict[str, Dict]:
raise web.HTTPFound(location=location)


class SwitchesCopyAdminView(web.View, CreateMixin):
validator = SwitchAddFromAnotherItsOnAdminPostRequestSchema()
model = switches

@staticmethod
async def _get_switches_data() -> MultiDictProxy:
async with ClientSession() as session:
async with session.get(settings.SYNC_FROM_ITS_ON_URL) as resp:
return await resp.json()

@login_required
async def post(self) -> None:
update_existing = bool(self.request.rel_url.query.get('update_existing'))
switches_data = await self._get_switches_data()
for switch_data in switches_data['result']:
await self._create_or_update_switch(switch_data, update_existing)

location = self.request.app.router['switches_list'].url_for()
raise web.HTTPFound(location=location)

async def _create_or_update_switch(
self, switch_data: MultiDictProxy, update_existing: bool = False,
) -> None:
try:
await self.create_object(self.request, switch_data)
except (ValidationError, psycopg2.IntegrityError):
if update_existing:
await self._update_switch(switch_data)

async def _update_switch(self, switch_data: MultiDictProxy) -> None:
async with self.request.app['db'].acquire() as conn:
update_query = (
self.model.update()
.where(self.model.c.name == switch_data['name'])
.values(switch_data)
)
try:
await conn.execute(update_query)
except (ValidationError, psycopg2.IntegrityError):
pass


class SwitchDeleteAdminView(web.View, GetObjectMixin):
model = switches

Expand Down
9 changes: 7 additions & 2 deletions its_on/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from dynaconf import settings

from auth.views import LoginView, LogoutView
from its_on.views import SwitchListView
from its_on.views import SwitchListView, SwitchFullListView
from its_on.admin.views.switches import (
SwitchListAdminView, SwitchDetailAdminView, SwitchDeleteAdminView, SwitchAddAdminView,
SwitchesCopyAdminView,
)
from its_on.admin.views.users import (
UserDetailAdminView, UserListAdminView,
Expand All @@ -23,14 +24,18 @@ def setup_routes(app: Application, base_dir: Path, cors_config: CorsConfig) -> N
app.router.add_view('/zbs/logout', LogoutView)
app.router.add_view('/zbs/switches', SwitchListAdminView, name='switches_list')
app.router.add_view('/zbs/switches/add', SwitchAddAdminView, name='switches_add')
app.router.add_view('/zbs/switches/copy', SwitchesCopyAdminView, name='switches_copy')
app.router.add_view('/zbs/switches/{id}', SwitchDetailAdminView, name='switch_detail')
app.router.add_view('/zbs/switches/{id}/delete', SwitchDeleteAdminView)
app.router.add_view('/zbs/users', UserListAdminView)
app.router.add_view('/zbs/users/{id}', UserDetailAdminView)

get_switch_view = app.router.add_view('/api/v1/switch', SwitchListView)

cors_config.add(get_switch_view)

if settings.ENABLE_SWITCHES_FULL_INFO_ENDPOINT:
get_switch_full_view = app.router.add_view('/api/v1/switches_full_info', SwitchFullListView)
cors_config.add(get_switch_full_view)

if settings.ENVIRONMENT == 'Dev':
app.router.add_static('/static', str(base_dir / 'its_on' / 'static'))
14 changes: 14 additions & 0 deletions its_on/schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ class SwitchListRequestSchema(Schema):
class SwitchListResponseSchema(Schema):
count = fields.Integer()
result = fields.List(fields.String)


class SwitchScheme(Schema):
name = fields.String()
is_active = fields.Boolean()
is_hidden = fields.Boolean()
group = fields.String()
groups = fields.List(fields.String)
version = fields.String()
comment = fields.String()


class SwitchFullListResponseSchema(Schema):
result = fields.List(fields.Nested(SwitchScheme))
9 changes: 9 additions & 0 deletions its_on/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ footer {
color: red;
}

.mx-5px {
margin-left: 5px;
margin-right: 5px;
}

.mr-0 {
margin-right: 0 !important;
}

.mt-10px {
margin-top: 10px;
}
Expand Down
14 changes: 11 additions & 3 deletions its_on/templates/switches/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

{% block content %}

<div class="col-sm-6">
<div class="col-sm-3">
<h2>Switches list</h2>
</div>
<div class="col-sm-3 mt-10px">
<a class="btn btn-primary float-right" href="{{ url('switches_add') }}">Add</a>
<div class="col-sm-6 mt-10px">
<a class="btn btn-primary float-right mx-5px mr-0" href="{{ url('switches_add') }}">Add</a>
{% if show_copy_button %}
<form action="{{ url('switches_copy') }}" method="POST" >
<input class="btn btn-success float-right mx-5px" type="submit" value="Copy from main (no rewrite)">
</form>
<form action="{{ url('switches_copy') }}?update_existing=true" method="POST" >
<input class="btn btn-info float-right mx-5px" type="submit" value="Copy from main (rewrite)">
</form>
{% endif %}
</div>

<div class="col-sm-9">
Expand Down
41 changes: 40 additions & 1 deletion its_on/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

from its_on.cache import switch_list_cache_key_builder
from its_on.models import switches
from its_on.schemes import SwitchListRequestSchema, SwitchListResponseSchema
from its_on.schemes import (
SwitchListRequestSchema, SwitchListResponseSchema, SwitchFullListResponseSchema,
)


class SwitchListView(CorsViewMixin, web.View):
Expand Down Expand Up @@ -56,3 +58,40 @@ async def filter_queryset(self, queryset: Select) -> Select:
filters.append(switches.c.version <= version)

return queryset.where(and_(*filters))


class SwitchFullListView(CorsViewMixin, web.View):
@docs(
summary='List of all active flags with full info.',
description='Returns a list of all active flags with all necessary info for recreation.',
)
@response_schema(SwitchFullListResponseSchema(), 200)
async def get(self) -> web.Response:
data = await self.get_response_data()
return web.json_response(data)

async def get_response_data(self) -> Dict:
objects = await self.load_objects()
data = [
{
'name': obj.name,
'is_active': obj.is_active,
'is_hidden': obj.is_hidden,
'groups': obj.groups,
'version': obj.version,
'comment': obj.comment,
}
for obj in objects
]
return {
'result': data,
}

async def load_objects(self) -> List:
async with self.request.app['db'].acquire() as conn:
queryset = self.get_queryset()
result = await conn.execute(queryset)
return await result.fetchall()

def get_queryset(self) -> Select:
return switches.select()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ webargs==5.5.3

pytest-cov==2.8.1
pytest-aiohttp==0.3.0
pytest-mock==3.1.0

pydocstyle==3.0.0
flake8==3.7.9
Expand Down
5 changes: 5 additions & 0 deletions settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ default:
cache_ttl: 300
redis_url: redis://127.0.0.1:6379/1
cors_allow_origin: ['http://localhost:8081']
enable_switches_full_info_endpoint: false
sync_from_its_on_url: '@none'

development:
environment: Dev
debug: true
enable_db_logging: true
cache_ttl: 1
enable_switches_full_info_endpoint: true
sync_from_its_on_url: http://localhost:8082/api/v1/switches_full_info

production:
environment: Prod
Expand All @@ -24,6 +28,7 @@ staging:

testing:
environment: Test
enable_switches_full_info_endpoint: true
database:
dsn: postgresql://bestdoctor:bestdoctor@localhost:5432/test_its_on
superuser_dsn: postgresql://bestdoctor:bestdoctor@localhost:5432/its_on
Expand Down
Loading

0 comments on commit f6cba09

Please sign in to comment.