tui
This commit is contained in:
parent
1946422b8a
commit
c9c2ce2733
|
@ -0,0 +1,24 @@
|
|||
from ceo.utils import http_get
|
||||
from .Controller import Controller
|
||||
from .SyncRequestController import SyncRequestController
|
||||
from ceo.tui.views import SearchGroupResponseView
|
||||
|
||||
|
||||
|
||||
class SearchGroupController(SyncRequestController):
|
||||
def __init__(self, model, app):
|
||||
super().__init__(model, app)
|
||||
|
||||
def get_resp(self):
|
||||
return http_get(f'/api/groups/search/{self.model.query}/{self.model.count}')
|
||||
|
||||
def get_response_view(self):
|
||||
return SearchGroupResponseView(self.model, self, self.app)
|
||||
|
||||
def on_next_button_pressed(self, button):
|
||||
try:
|
||||
self.model.query = self.get_username_from_view()
|
||||
#self.model.count = 10
|
||||
except Controller.InvalidInput:
|
||||
return
|
||||
self.on_confirmation_button_pressed(button)
|
|
@ -8,6 +8,7 @@ from .ResetPasswordController import ResetPasswordController
|
|||
from .ChangeLoginShellController import ChangeLoginShellController
|
||||
from .AddGroupController import AddGroupController
|
||||
from .GetGroupController import GetGroupController
|
||||
from .SearchGroupController import SearchGroupController
|
||||
from .AddMemberToGroupController import AddMemberToGroupController
|
||||
from .RemoveMemberFromGroupController import RemoveMemberFromGroupController
|
||||
from .CreateDatabaseController import CreateDatabaseController
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class SearchGroupModel:
|
||||
name = 'SearchGroup'
|
||||
title = 'Search groups'
|
||||
|
||||
def __init__(self):
|
||||
self.query = ''
|
||||
self.count = 10
|
||||
self.resp_json = None
|
|
@ -5,6 +5,7 @@ from .ResetPasswordModel import ResetPasswordModel
|
|||
from .ChangeLoginShellModel import ChangeLoginShellModel
|
||||
from .AddGroupModel import AddGroupModel
|
||||
from .GetGroupModel import GetGroupModel
|
||||
from .SearchGroupModel import SearchGroupModel
|
||||
from .AddMemberToGroupModel import AddMemberToGroupModel
|
||||
from .RemoveMemberFromGroupModel import RemoveMemberFromGroupModel
|
||||
from .CreateDatabaseModel import CreateDatabaseModel
|
||||
|
@ -29,6 +30,7 @@ class WelcomeModel:
|
|||
'Groups': [
|
||||
AddGroupModel,
|
||||
GetGroupModel,
|
||||
SearchGroupModel,
|
||||
AddMemberToGroupModel,
|
||||
RemoveMemberFromGroupModel,
|
||||
],
|
||||
|
|
|
@ -6,6 +6,7 @@ from .ResetPasswordModel import ResetPasswordModel
|
|||
from .ChangeLoginShellModel import ChangeLoginShellModel
|
||||
from .AddGroupModel import AddGroupModel
|
||||
from .GetGroupModel import GetGroupModel
|
||||
from .SearchGroupModel import SearchGroupModel
|
||||
from .AddMemberToGroupModel import AddMemberToGroupModel
|
||||
from .RemoveMemberFromGroupModel import RemoveMemberFromGroupModel
|
||||
from .CreateDatabaseModel import CreateDatabaseModel
|
||||
|
|
|
@ -25,6 +25,7 @@ def handle_sync_response(resp, controller):
|
|||
raise Controller.RequestFailed()
|
||||
|
||||
|
||||
# this can probably be simplified with getattr or something
|
||||
def get_mvc(app, name):
|
||||
if name == WelcomeModel.name:
|
||||
model = WelcomeModel()
|
||||
|
@ -58,6 +59,10 @@ def get_mvc(app, name):
|
|||
model = GetGroupModel()
|
||||
controller = GetGroupController(model, app)
|
||||
view = GetGroupView(model, controller, app)
|
||||
elif name == SearchGroupModel.name:
|
||||
model = SearchGroupModel()
|
||||
controller = SearchGroupController(model, app)
|
||||
view = SearchGroupView(model, controller, app)
|
||||
elif name == AddMemberToGroupModel.name:
|
||||
model = AddMemberToGroupModel()
|
||||
controller = AddMemberToGroupController(model, app)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import urwid
|
||||
|
||||
from .ColumnResponseView import ColumnResponseView
|
||||
|
||||
|
||||
|
||||
class SearchGroupResponseView(ColumnResponseView):
|
||||
def __init__(self, model, controller, app):
|
||||
super().__init__(model, controller,app)
|
||||
l = self.model.resp_json.copy()
|
||||
#rows = [(urwid.Text(str(i) + ':', align='right'), urwid.Text(resp)) for i, resp in enumerate(l)]
|
||||
rows = [(str(i), resp) for i, resp in enumerate(l)]
|
||||
self.set_pairs(rows)
|
|
@ -0,0 +1,16 @@
|
|||
import urwid
|
||||
|
||||
from .ColumnView import ColumnView
|
||||
|
||||
class SearchGroupView(ColumnView):
|
||||
def __init__(self, model, controller, app):
|
||||
super().__init__(model, controller, app)
|
||||
# used for query, consider combining Controller.user_name_from_view and Controller.get_group_name_from_view
|
||||
self.username_edit = urwid.Edit()
|
||||
rows = [
|
||||
(
|
||||
urwid.Text('Query:', align='right'),
|
||||
self.username_edit
|
||||
)
|
||||
]
|
||||
self.set_rows(rows)
|
|
@ -16,6 +16,8 @@ from .AddGroupView import AddGroupView
|
|||
from .AddGroupConfirmationView import AddGroupConfirmationView
|
||||
from .GetGroupView import GetGroupView
|
||||
from .GetGroupResponseView import GetGroupResponseView
|
||||
from .SearchGroupView import SearchGroupView
|
||||
from .SearchGroupResponseView import SearchGroupResponseView
|
||||
from .AddMemberToGroupView import AddMemberToGroupView
|
||||
from .AddMemberToGroupConfirmationView import AddMemberToGroupConfirmationView
|
||||
from .RemoveMemberFromGroupView import RemoveMemberFromGroupView
|
||||
|
|
|
@ -12,6 +12,8 @@ from ceod.transactions.groups import (
|
|||
DeleteGroupTransaction,
|
||||
)
|
||||
|
||||
from heapq import heappushpop, nlargest
|
||||
|
||||
bp = Blueprint('groups', __name__)
|
||||
|
||||
|
||||
|
@ -32,12 +34,52 @@ def get_group(group_name):
|
|||
group = ldap_srv.get_group(group_name)
|
||||
return group.to_dict()
|
||||
|
||||
@bp.route('/clubs')
|
||||
def get_clubs():
|
||||
|
||||
@bp.route('/search/<query>/<count>')
|
||||
def search_group(query, count):
|
||||
# compute levenshtein edit distance, adapted from rosetta code
|
||||
def _fuzzy_match(s1, s2):
|
||||
if len(s1) == 0: return len(s2)
|
||||
if len(s2) == 0: return len(s1)
|
||||
edits = [i for i in range(len(s2) + 1)]
|
||||
for i in range(len(s1)):
|
||||
corner = i
|
||||
edits[0] = i + 1
|
||||
for j in range(len(s2)):
|
||||
upper = edits[j + 1]
|
||||
if s1[i] == s2[j]:
|
||||
edits[j + 1] = corner
|
||||
else:
|
||||
m = min(corner, upper, edits[j])
|
||||
edits[j + 1] = m + 1
|
||||
corner = upper
|
||||
return edits[-1]
|
||||
|
||||
class _fuzzy_result:
|
||||
def __init__(self, string, score):
|
||||
self.string = string
|
||||
self.score = score
|
||||
# consider a score worse if the edit distance is larger
|
||||
def __lt__(self, other): return self.score > other.score
|
||||
def __gt__(self, other): return self.score < other.score
|
||||
def __le__(self, other): return self.score >= other.score
|
||||
def __ge__(self, other): return self.score <= other.score
|
||||
def __eq__(self, other): return self.score == other.score
|
||||
def __ne__(self, other): return self.score != other.score
|
||||
|
||||
query = str(query)
|
||||
count = int(count)
|
||||
ldap_srv = component.getUtility(ILDAPService)
|
||||
clubs = ldap_srv.get_clubs()
|
||||
#return jsonify([club.to_dict() for club in clubs])
|
||||
return jsonify(clubs)
|
||||
scores = [_fuzzy_result("", 99999) for _ in range(count)]
|
||||
for club in clubs:
|
||||
score = _fuzzy_match(query, str(club.cn))
|
||||
result = _fuzzy_result(str(club.cn), score)
|
||||
heappushpop(scores, result)
|
||||
|
||||
result = [score.string for score in nlargest(count, scores)]
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@bp.route('/<group_name>/members/<username>', methods=['POST'])
|
||||
@authz_restrict_to_syscom
|
||||
|
|
Loading…
Reference in New Issue