示例#1
0
文件: roles.py 项目: knowark/authark
 def _switch(self, item: Optional[Dict[str, Any]],
             source: Listbox, target: Listbox) -> None:
     if item and item in source.data:
         source.data.remove(item)
         source.connect()
     if item and item not in target.data:
         target.data.insert(0, item)
         target.connect()
示例#2
0
文件: roles.py 项目: knowark/authark
class UsersSelectionModal(Modal):
    def setup(self, **context) -> 'RoleDetailsModal':
        self.injector = context['injector']
        self.authark_informer = self.injector['StandardInformer']
        self.management_manager = self.injector['ManagementManager']
        self.role = context['role']
        self.focused: Dict = {}
        self.available_domain: List = []
        self.chosen_domain: List = []
        return super().setup(**context) and self

    def build(self) -> None:
        super().build()
        self.modal = None

        available_frame = Frame(self, title='Available').weight(
            5, 4).grid(0, 0)
        self.available_search = Entry(
            available_frame, command=self.on_available_search).listen(
                'keydown', self.on_available_search, True).weight(
                    col=2).grid(0, 0)
        self.available_total = Label(
            available_frame, content='Total: 0').grid(0, 1)
        self.available = Listbox(
            available_frame, command=self.on_select).weight(
                9).span(col=2).grid(1)

        switchers = Frame(self).title_style(
            Color.SUCCESS()).style(border=[]).weight(5).grid(0, 1)

        Button(switchers, content='\U000025B6', command=self.on_choose).style(
            Color.SUCCESS(), border=[], template='{}').grid(0)
        Button(switchers, content='\U000025C0', command=self.on_clear).style(
            Color.SUCCESS(), border=[], template='{}').grid(1)
        Button(switchers, content='\U000023E9',
               command=self.on_choose_all).style(
            Color.SUCCESS(), border=[], template='{}').grid(2)
        Button(switchers, content='\U000023EA',
               command=self.on_clear_all).style(
            Color.SUCCESS(), border=[], template='{}').grid(3)

        chosen_frame = Frame(self, title='Chosen').weight(
            5, 4).grid(0, 2)
        self.chosen_search = Entry(chosen_frame).listen(
            'keydown', self.on_chosen_search, True).weight(col=2).grid(0, 0)
        self.chosen_total = Label(
            chosen_frame, content='Total: 0').grid(0, 1)
        self.chosen = Listbox(
            chosen_frame, command=self.on_select).weight(
                9).span(col=2).grid(1)

        actions = Frame(
            self, title='Actions').title_style(
                Color.WARNING()).grid(1).span(col=3)
        Label(actions, content=f'Role: {self.role["name"]}').grid(0, 2)
        Spacer(actions).grid(0, 3).weight(col=1)
        Button(actions, content='Save', command=self.on_save
               ).style(Color.SUCCESS()).grid(0, 4)
        Button(actions, content='Cancel', command=self.on_cancel
               ).style(Color.WARNING()).grid(0, 5)

    async def on_select(self, event: Event) -> None:
        item = getattr(event.target.parent, 'item', None)
        event.target.focus()
        self.focused = item if isinstance(item, dict) else {}

    async def on_available_search(self, event: Event) -> None:
        if event.key == '\n':
            event.stop = True
            text = self.available_search.text.strip()
            self.available.offset = 0
            self.available_domain = [] if not text else [
                '|',  ('name', 'ilike', f'%{text}%'),
                ('email', 'ilike', f'%{text}%')]
            await self.load()
            self.available_search.focus()

    async def on_chosen_search(self, event: Event) -> None:
        if event.key == '\n':
            event.stop = True
            text = self.chosen_search.text.strip()
            self.chosen.offset = 0
            self.chosen_domain = [] if not text else [
                '|',  ('name', 'ilike', f'%{text}%'),
                ('email', 'ilike', f'%{text}%')]
            await self.load()
            self.chosen_search.focus()

    async def load(self) -> None:
        current_user_ids = [ranking['user_id'] for ranking in
                            (await self.authark_informer.search({
                                "meta": {
                                    "model": "ranking",
                                    "domain": [
                                        ('role_id', '=', self.role['id'])]
                                }
                                }))['data']
                            ]
        available_users = (await self.authark_informer.search({
            "meta": {
                "model": "user",
                "domain": [
            '!', ('id', 'in', current_user_ids)] + self.available_domain
            }
        }))['data']
        chosen_users = (await self.authark_informer.search({
            "meta": {
                "model": "user",
                "domain": [
            ('id', 'in', current_user_ids)] + self.chosen_domain
            }
        }))['data']

        self.available.setup(data=available_users,
                             fields=['username', 'email'],
                             limit=20).connect()
        self.chosen.setup(data=chosen_users,
                          fields=['username', 'email'],
                          limit=20).connect()
        self._update_totals()

    async def on_choose(self, event: Event) -> None:
        self._switch(self.focused, self.available, self.chosen)
        self._update_totals()

    async def on_choose_all(self, event: Event) -> None:
        self.chosen.data = list(self.available.data + self.chosen.data)
        self.available.data = []
        self.chosen.connect()
        self.available.connect()
        self._update_totals()

    async def on_clear(self, event: Event) -> None:
        self._switch(self.focused, self.chosen, self.available)
        self._update_totals()

    async def on_clear_all(self, event: Event) -> None:
        self.available.data = list(self.available.data + self.chosen.data)
        self.chosen.data = []
        self.available.connect()
        self.chosen.connect()
        self._update_totals()

    def _update_totals(self) -> None:
        self.available_total.setup(
            content=f'Total: {len(self.available.data)}').render()
        self.chosen_total.setup(
            content=f'Total: {len(self.chosen.data)}').render()

    def _switch(self, item: Optional[Dict[str, Any]],
                source: Listbox, target: Listbox) -> None:
        if item and item in source.data:
            source.data.remove(item)
            source.connect()
        if item and item not in target.data:
            target.data.insert(0, item)
            target.connect()

    async def on_save(self, event: Event) -> None:
        removing_ranking_ids = [
            ranking['id'] for ranking in (await self.authark_informer.search({
                "meta": {
                    "model": "ranking",
                    "domain": [('role_id', '=', self.role['id']),
                            ('user_id', 'in', [user['id'] for user in
                                               self.available.data])]
                    }
                }))['data']
        ]
        await self.management_manager.deassign_role(removing_ranking_ids)
        adding_rankings = [{'role_id': self.role['id'], 'user_id': user['id']}
                           for user in self.chosen.data]
        await self.management_manager.assign_role({
            "meta": {},
            "data": adding_rankings
        })
        await self.done({'result': 'saved'})

    async def on_cancel(self, event: Event) -> None:
        await self.done({'result': 'cancelled'})