positions api
This commit is contained in:
parent
8dcada4090
commit
4e578d0401
|
@ -7,6 +7,11 @@ First, make sure that you have installed the
|
|||
This will setup all of the services needed for ceo to work. You should clone
|
||||
this repo in one of the dev environment containers.
|
||||
|
||||
Install required system package for pyceo:
|
||||
```sh
|
||||
apt install libkrb5-dev libsasl2-dev libldap2-dev
|
||||
```
|
||||
|
||||
Next, install and activate a virtualenv:
|
||||
```sh
|
||||
sudo apt install libkrb5-dev python3-dev
|
||||
|
|
|
@ -18,6 +18,9 @@ class ILDAPService(Interface):
|
|||
def get_user(username: str) -> IUser:
|
||||
"""Retrieve the user with the given username."""
|
||||
|
||||
def get_users_with_positions(self) -> List[IUser]:
|
||||
"""Retrieve users who has their position set"""
|
||||
|
||||
def add_user(user: IUser):
|
||||
"""
|
||||
Add the user to the database.
|
||||
|
|
|
@ -31,8 +31,9 @@ def create_app(flask_config={}):
|
|||
# Only ceod_admin_host should serve the /api/members endpoints because
|
||||
# it needs to run kadmin
|
||||
if hostname == cfg.get('ceod_admin_host'):
|
||||
from ceod.api import members
|
||||
from ceod.api import members, positions
|
||||
app.register_blueprint(members.bp, url_prefix='/api/members')
|
||||
app.register_blueprint(positions.bp, url_prefix='/api/positions')
|
||||
|
||||
if hostname == cfg.get('ceod_mailman_host'):
|
||||
# Only offer mailman API if this host is running Mailman
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import json
|
||||
from flask import Blueprint, request
|
||||
from zope import component
|
||||
|
||||
from ceod.transactions.members import UpdateMemberPositionsTransaction
|
||||
from .utils import authz_restrict_to_syscom, requires_authentication_no_realm, create_streaming_response
|
||||
from ceo_common.interfaces import ILDAPService
|
||||
|
||||
bp = Blueprint('positions', __name__)
|
||||
|
||||
@bp.route('/', methods=['GET'])
|
||||
@requires_authentication_no_realm
|
||||
def get_positions(auth_user: str):
|
||||
ldap_srv = component.getUtility(ILDAPService)
|
||||
|
||||
users = ldap_srv.get_users_with_positions()
|
||||
|
||||
positions = {}
|
||||
for user in users:
|
||||
for position in user.positions:
|
||||
positions[position] = user.uid
|
||||
|
||||
return json.dumps(positions)
|
||||
|
||||
@bp.route('/', methods=['POST'])
|
||||
@authz_restrict_to_syscom
|
||||
def update_positions():
|
||||
body = request.get_json(force=True)
|
||||
# TODO verify json
|
||||
|
||||
# Reverse the dict so it's easier to use
|
||||
member_positions = {}
|
||||
for position, user in body.items():
|
||||
if user not in member_positions:
|
||||
member_positions[user] = []
|
||||
member_positions[user].append(position)
|
||||
|
||||
txn = UpdateMemberPositionsTransaction(member_positions)
|
||||
return create_streaming_response(txn)
|
||||
|
||||
# TODO un/subscribe to mailing list
|
|
@ -82,6 +82,11 @@ class LDAPService:
|
|||
entry = self._get_readable_entry_for_group(conn, cn)
|
||||
return Group.deserialize_from_ldap(entry)
|
||||
|
||||
def get_users_with_positions(self) -> List[IUser]:
|
||||
conn = self._get_ldap_conn(False)
|
||||
conn.search(self.ldap_users_base, '(position=*)', attributes=ldap3.ALL_ATTRIBUTES)
|
||||
return [User.deserialize_from_ldap(entry) for entry in conn.entries]
|
||||
|
||||
def uid_to_dn(self, uid: str):
|
||||
return f'uid={uid},{self.ldap_users_base}'
|
||||
|
||||
|
|
|
@ -168,6 +168,11 @@ class User:
|
|||
entry.position.delete(position)
|
||||
self.positions.remove(position)
|
||||
|
||||
def set_positions(self, positions: List[str]):
|
||||
with self.ldap_srv.entry_ctx_for_user(self) as entry:
|
||||
entry.position = positions
|
||||
self.positions = positions
|
||||
|
||||
def get_forwarding_addresses(self) -> List[str]:
|
||||
return self.file_srv.get_forwarding_addresses(self)
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
from typing import List, Dict
|
||||
|
||||
from zope import component
|
||||
|
||||
from ..AbstractTransaction import AbstractTransaction
|
||||
from ceo_common.interfaces import ILDAPService
|
||||
|
||||
class UpdateMemberPositionsTransaction(AbstractTransaction):
|
||||
"""
|
||||
Transaction to update member's positions, and remove positions for anyone that's not in the list
|
||||
"""
|
||||
|
||||
# Positions is a dict where keys are member names and values are the list of positions they have
|
||||
def __init__(self, positions: Dict[str, List[str]]):
|
||||
super().__init__()
|
||||
self.positions = positions
|
||||
self.ldap_srv = component.getUtility(ILDAPService)
|
||||
self.old_positions = {}
|
||||
|
||||
def child_execute_iter(self):
|
||||
for username, positions in self.positions.items():
|
||||
user = self.ldap_srv.get_user(username)
|
||||
user.set_positions(positions)
|
||||
yield f'update_positions_{username}'
|
||||
self.finish(None)
|
||||
|
||||
def rollback(self):
|
||||
# TODO
|
||||
pass
|
|
@ -2,3 +2,4 @@ from .AddMemberTransaction import AddMemberTransaction
|
|||
from .ModifyMemberTransaction import ModifyMemberTransaction
|
||||
from .RenewMemberTransaction import RenewMemberTransaction
|
||||
from .DeleteMemberTransaction import DeleteMemberTransaction
|
||||
from .UpdateMemberPositionsTransaction import UpdateMemberPositionsTransaction
|
||||
|
|
Loading…
Reference in New Issue