Package Gnumed :: Package business :: Module gmStaff |
[frames] | no frames]

# Source Code for Module Gnumed.business.gmStaff

      1  # -*- coding: utf-8 -*-
      2  """GNUmed staff objects."""
      3  #============================================================
      4  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
      5  __license__ = "GPL"
      6
      7  # std lib
      8  import sys
      9  import logging
     10
     11  # GNUmed
     12  if __name__ == '__main__':
     13          sys.path.insert(0, '../../')
     14  from Gnumed.pycommon import gmBusinessDBObject
     15  from Gnumed.pycommon import gmPG2
     16  from Gnumed.pycommon import gmNull
     17  from Gnumed.pycommon import gmBorg
     18  from Gnumed.pycommon import gmLog2
     19
     20
     21  _log = logging.getLogger('gm.staff')
     22
     23  _map_gm_role2pg_group = {
     24          'public access': 'gm-public',
     25          'non-clinical access': 'gm-staff',
     26          'full clinical access': 'gm-doctors'
     27  }
     28
     29  #============================================================
     30  _SQL_get_staff_fields = 'SELECT *, _(role) AS l10n_role FROM dem.v_staff WHERE %s'
     31
     32 -class cStaff(gmBusinessDBObject.cBusinessDBObject):
     33          _cmd_fetch_payload = _SQL_get_staff_fields % "pk_staff = %s"
     34          _cmds_store_payload = [
     35                  """UPDATE dem.staff SET
     36                                  short_alias = %(short_alias)s,
     37                                  comment = gm.nullify_empty_string(%(comment)s),
     38                                  is_active = %(is_active)s,
     39                                  db_user = %(db_user)s
     40                          WHERE
     41                                  pk = %(pk_staff)s
     42                                          AND
     43                                  xmin = %(xmin_staff)s
     44                          RETURNING
     45                                  xmin AS xmin_staff"""
     46          ]
     47          _updatable_fields = ['short_alias', 'comment', 'is_active', 'db_user']
     48
     49          #--------------------------------------------------------
     50 -        def __init__(self, aPK_obj=None, row=None):
     51                  # by default get staff corresponding to CURRENT_USER
     52                  if (aPK_obj is None) and (row is None):
     53                          cmd = _SQL_get_staff_fields % "db_user = CURRENT_USER"
     54                          try:
     55                                  rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
     56                          except:
     57                                  _log.exception('cannot instantiate staff instance')
     58                                  gmLog2.log_stack_trace()
     59                                  raise ValueError('cannot instantiate staff instance for database account CURRENT_USER')
     60                          if len(rows) == 0:
     61                                  raise ValueError('no staff record for database account CURRENT_USER')
     62                          row = {
     63                                  'pk_field': 'pk_staff',
     64                                  'idx': idx,
     65                                  'data': rows[0]
     66                          }
     67                          gmBusinessDBObject.cBusinessDBObject.__init__(self, row = row)
     68                  else:
     69                          gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj = aPK_obj, row = row)
     70
     71                  # are we SELF ?
     72                  self.__is_current_user = (gmPG2.get_current_user() == self._payload[self._idx['db_user']])
     73
     74                  self.__inbox = None
     75
     76          #--------------------------------------------------------
     77 -        def __setitem__(self, attribute, value):
     78                  if attribute == 'db_user':
     79                          if self.__is_current_user:
     80                                  _log.debug('will not modify database account association of CURRENT_USER staff member')
     81                                  return
     82                  gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
     83
     84          #--------------------------------------------------------
     85 -        def _get_db_lang(self):
     86                  rows, idx = gmPG2.run_ro_queries (
     87                          queries = [{
     88                                  'cmd': 'select i18n.get_curr_lang(%(usr)s)',
     89                                  'args': {'usr': self._payload[self._idx['db_user']]}
     90                          }]
     91                  )
     92                  return rows[0][0]
     93
     94 -        def _set_db_lang(self, language):
     95                  if not gmPG2.set_user_language(language = language):
     96                          raise ValueError (
     97                                  'Cannot set database language to [%s] for user [%s].' % (language, self._payload[self._idx['db_user']])
     98                          )
     99                  return
    100
    101          database_language = property(_get_db_lang, _set_db_lang)
    102
    103          #--------------------------------------------------------
    104 -        def _get_inbox(self):
    105                  if self.__inbox is None:
    106                          from Gnumed.business import gmProviderInbox
    107                          self.__inbox = gmProviderInbox.cProviderInbox(provider_id = self._payload[self._idx['pk_staff']])
    108                  return self.__inbox
    109
    110 -        def _set_inbox(self, inbox):
    111                  return
    112
    113          inbox = property(_get_inbox, _set_inbox)
    114
    115          #--------------------------------------------------------
    116 -        def _get_identity(self):
    117                  from Gnumed.business.gmPerson import cPerson
    118                  return cPerson(self._payload[self._idx['pk_identity']])
    119
    120          identity = property(_get_identity, lambda x:x)
    121
    122          #--------------------------------------------------------
    123 -        def set_role(self, conn=None, role=None):
    124                  if role.strip() == self._payload[self._idx['role']]:
    125                          return True
    126
    127                  cmd = 'SELECT gm.add_user_to_permission_group(%(usr)s::name, %(grp)s::name)'
    128                  args = {
    129                          'usr': self._payload[self._idx['db_user']],
    130                          'grp': _map_gm_role2pg_group[role.strip()]
    131                  }
    132                  rows, idx = gmPG2.run_rw_queries (
    133                          link_obj = conn,
    134                          queries = [{'cmd': cmd, 'args': args}],
    135                          get_col_idx = False,
    136                          return_data = True,
    137                          end_tx = True
    138                  )
    139                  if not rows[0][0]:
    140                          return False
    141                  self.refetch_payload()
    142                  return True
    143
    144          role = property(lambda x:x, set_role)
    145
    146  #============================================================
    147 -def get_staff_list(active_only=False):
    148          if active_only:
    149                  cmd = _SQL_get_staff_fields % 'is_active ORDER BY can_login DESC, short_alias ASC'
    150          else:
    151                  cmd = _SQL_get_staff_fields % 'TRUE ORDER BY can_login DESC, is_active DESC, short_alias ASC'
    152          rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
    153          staff_list = []
    154          for row in rows:
    155                  obj_row = {
    156                          'idx': idx,
    157                          'data': row,
    158                          'pk_field': 'pk_staff'
    159                  }
    160                  staff_list.append(cStaff(row=obj_row))
    161          return staff_list
    162
    163  #------------------------------------------------------------
    164 -def create_staff(conn=None, db_account=None, password=None, identity=None, short_alias=None):
    165          args = {
    166                  'pg_usr': db_account,
    167                  'pwd': password,
    168                  'person_id': identity,
    169                  'sig': short_alias
    170          }
    171
    172          queries = [
    173                  {'cmd': 'SELECT gm.create_user(%(pg_usr)s, %(pwd)s)', 'args': args},
    174                  {'cmd': """
    175                          INSERT INTO dem.staff
    176                                  (fk_identity, db_user, short_alias)
    177                          VALUES (
    178                                  %(person_id)s,
    179                                  %(pg_usr)s,
    180                                  %(sig)s
    181                          )""",
    182                   'args': args
    183                  }
    184          ]
    185
    186          try:
    187                  rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = queries, end_tx = True)
    188          except gmPG2.dbapi.IntegrityError as e:
    189                  if e.pgcode == gmPG2.sql_error_codes.UNIQUE_VIOLATION:
    190                          msg = _(
    191                                  'Cannot add GNUmed user.\n'
    192                                  '\n'
    193                                  'The database account [%s] is already listed as a\n'
    194                                  'GNUmed user. There can only be one GNUmed user\n'
    195                                  'for each database account.\n'
    196                          ) % db_account
    197                          return False, msg
    198                  raise
    199
    200          return True, None
    201
    202  #------------------------------------------------------------
    203 -def delete_staff(conn=None, pk_staff=None):
    204          queries = [{'cmd': 'DELETE FROM dem.staff WHERE pk = %(pk)s', 'args': {'pk': pk_staff}}]
    205          try:
    206                  rows, idx = gmPG2.run_rw_queries(link_obj = conn, queries = queries, end_tx = True)
    207          except gmPG2.dbapi.IntegrityError as e:
    208                  if e.pgcode == gmPG2.sql_error_codes.FOREIGN_KEY_VIOLATION:             # 23503  foreign_key_violation
    209                          msg = _(
    210                                  'Cannot delete GNUmed staff member because the\n'
    211                                  'database still contains data linked to it.\n'
    212                                  '\n'
    213                                  'The account was deactivated instead.'
    214                          )
    215                          deactivate_staff(conn = conn, pk_staff = pk_staff)
    216                          return False, msg
    217                  raise
    218
    219          return True, None
    220
    221  #------------------------------------------------------------
    222 -def activate_staff(conn=None, pk_staff=None):
    223          # 1) activate staff entry
    224          staff = cStaff(aPK_obj = pk_staff)
    225          staff['is_active'] = True
    226          staff.save_payload(conn=conn)                           # FIXME: error handling
    227
    228          # 2) enable database account login
    229          rowx, idx = gmPG2.run_rw_queries (
    230                  link_obj = conn,
    231                  # password does not matter because PG account must already exist
    232                  queries = [{'cmd': 'select gm.create_user(%s, %s)', 'args': [staff['db_user'], 'flying wombat']}],
    233                  end_tx = True
    234          )
    235
    236          return True
    237
    238  #------------------------------------------------------------
    239 -def deactivate_staff(conn=None, pk_staff=None):
    240
    241          # 1) inactivate staff entry
    242          staff = cStaff(aPK_obj = pk_staff)
    243          staff['is_active'] = False
    244          staff.save_payload(conn = conn)                         # FIXME: error handling
    245
    246          # 2) disable database account login
    247          rows, idx = gmPG2.run_rw_queries (
    248                  link_obj = conn,
    249                  queries = [{'cmd': 'select gm.disable_user(%s)', 'args': [staff['db_user']]}],
    250                  end_tx = True
    251          )
    252
    253          return True
    254
    255  #============================================================
    256 -def set_current_provider_to_logged_on_user():
    257          gmCurrentProvider(provider = cStaff())
    258
    259  #============================================================
    260 -class gmCurrentProvider(gmBorg.cBorg):
    261          """Staff member Borg to hold currently logged on provider.
    262
    263          There may be many instances of this but they all share state.
    264          """
    265 -        def __init__(self, provider=None):
    266                  """Change or get currently logged on provider.
    267
    268                  provider:
    269                  * None: get copy of current instance
    270                  * cStaff instance: change logged on provider (role)
    271                  """
    272                  # make sure we do have a provider pointer
    273                  try:
    274                          self.provider
    275                  except AttributeError:
    276                          self.provider = gmNull.cNull()
    277
    278                  # user wants copy of currently logged on provider
    279                  if provider is None:
    280                          return None
    281
    282                  # must be cStaff instance, then
    283                  if not isinstance(provider, cStaff):
    284                          raise ValueError('cannot set logged on provider to [%s], must be either None or cStaff instance' % str(provider))
    285
    286                  # first invocation
    287                  if isinstance(self.provider, gmNull.cNull):
    288                          self.provider = provider
    289                          return None
    290
    291                  # same ID, no change needed
    292                  if self.provider['pk_staff'] == provider['pk_staff']:
    293                          return None
    294
    295                  # user wants different provider
    296                  raise ValueError('provider change [%s] -> [%s] not yet supported' % (self.provider['pk_staff'], provider['pk_staff']))
    297
    298          #--------------------------------------------------------
    299 -        def get_staff(self):
    300                  return self.provider
    301
    302          #--------------------------------------------------------
    303          # __getitem__ handling
    304          #--------------------------------------------------------
    305 -        def __getitem__(self, aVar):
    306                  """Return any attribute if known how to retrieve it by proxy.
    307                  """
    308                  return self.provider[aVar]
    309
    310          #--------------------------------------------------------
    311          # __s/getattr__ handling
    312          #--------------------------------------------------------
    313 -        def __getattr__(self, attribute):
    314                  if attribute == 'provider':                     # so we can __init__ ourselves
    315                          raise AttributeError
    316                  if not isinstance(self.provider, gmNull.cNull):
    317                          return getattr(self.provider, attribute)
    318  #               raise AttributeError
    319
    320  #============================================================
    321  # main/testing
    322  #============================================================
    323  if __name__ == '__main__':
    324
    325          if len(sys.argv) == 1:
    326                  sys.exit()
    327
    328          if sys.argv[1] != 'test':
    329                  sys.exit()
    330
    331          import datetime
    332          from Gnumed.pycommon import gmI18N
    333          from Gnumed.pycommon import gmDateTime
    334
    335          gmI18N.activate_locale()
    336          gmI18N.install_domain()
    337          gmDateTime.init()
    338
    339          #--------------------------------------------------------
    340 -        def test_staff():
    341                  staff = cStaff()
    342                  print(staff)
    343                  print(staff.inbox)
    344                  print(staff.inbox.messages)
    345          #--------------------------------------------------------
    346 -        def test_current_provider():
    347                  staff = cStaff()
    348                  provider = gmCurrentProvider(provider = staff)
    349                  print(provider)
    350                  print(provider.inbox)
    351                  print(provider.inbox.messages)
    352                  print(provider.database_language)
    353                  tmp = provider.database_language
    354                  provider.database_language = None
    355                  print(provider.database_language)
    356                  provider.database_language = tmp
    357                  print(provider.database_language)
    358          #--------------------------------------------------------
    359          test_staff()
    360          #test_current_provider()
    361
    362  #============================================================
    363