Beispiel #1
0
class Subject(CreatedModified):
    '''
    This class represents a master patient index for the eHB system. It serves as the
    primary key for linking a given subject stored in the eHB to all other records stored in
    external systems
    '''
    first_name = EncryptCharField(max_length=50, verbose_name='First Name')
    last_name = EncryptCharField(max_length=70, verbose_name='Last Name')
    # This is the organization that created the subject record, e.g. CHOP
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
    # This is the organization's id for this subject, e.g. MRN value
    organization_subject_id = EncryptCharField(max_length=120, verbose_name='Organization Subject Record ID')
    dob = EncryptDateField(verbose_name='Date Of Birth', help_text=date_help_text)
    cleanmsg = 'There is already a Subject for this Organization and Subject ID'

    class Meta(CreatedModified.Meta):
        ordering = ['organization', 'organization_subject_id']

    # class Meta(CreatedModified.Meta):
    #    unique_together=('organization','organization_subject_id')
    # I WOULD LIKE TO USE THE META ABOVE BUT RIGHT NOW THAT BREAKS THE ehb-client WHEN TRYING UPDATE AN EXTERNAL_RECORD

    def clean(self):
        try:
            subs = Subject.objects.filter(
                organization_subject_id=self.organization_subject_id).filter(
                organization=self.organization)

            for sub in subs:
                if sub.pk != self.pk:  # if they are equal then we are modifying this record
                    raise ValidationError(self.cleanmsg)

        except Organization.DoesNotExist:
            pass  # The Organization field validation will handle this

    def responseFieldDict(self):
        response = {}
        response['created'] = self.created.strftime('%Y-%m-%d %H:%M:%S.%f')
        response['modified'] = self.modified.strftime('%Y-%m-%d %H:%M:%S.%f')
        response['first_name'] = self.first_name
        response['last_name'] = self.last_name
        response['organization'] = self.organization_id
        response['id'] = self.id
        response['organization_subject_id'] = self.organization_subject_id
        response['organization_id_label'] = self.organization.subject_id_label
        response['dob'] = self.dob.strftime('%Y-%m-%d')

        return response

    def __str__(self):
        return "{0}, {1} : {2} : {3}".format(
            self.last_name,
            self.first_name,
            self.organization.name,
            self.organization_subject_id
        )
Beispiel #2
0
class GroupEhbKey(GroupPropsKey):

    key = EncryptCharField(max_length=255,
                           unique=True,
                           verbose_name='EHB KEY',
                           editable=False,
                           blank=True)

    def _make_random_key(self,
                         seed,
                         ja,
                         l,
                         chars=string.ascii_uppercase + string.digits):
        random.seed(seed)
        for i in range(ja):
            dummy = random.random()
        return ''.join(random.choice(chars) for idx in range(l))

    def _set_key(self):
        '''Generate a unique key'''
        if not self.pk:
            ehb_key_length = self._ehb_key_length()
            seed = self._ehb_key_seed()
            jump = GroupEhbKey.objects.count()
            # Generate a new key, overriding any key that was used to create this object
            uk = ''
            idx = 0
            max_idx = 1e6
            while idx < max_idx:
                uk = self._make_random_key(seed=seed,
                                           ja=jump + idx,
                                           l=ehb_key_length)
                if not GroupEhbKey.objects.all():
                    idx = max_idx
                else:
                    grps_using_uk = GroupEhbKey.objects.filter(key=uk)
                    if grps_using_uk.count() == 0:
                        idx = max_idx
                    else:
                        idx += 1
            self.key = uk

    def _ehb_key_seed(self, default=123456789):
        return self.ehb_prop('EHB_GROUP_EHB_KEYS', 'seed', default)

    def _ehb_key_length(self, default=15):
        return self.ehb_prop('EHB_GROUP_EHB_KEYS', 'length', default)

    def save(self, force_insert=False, force_update=False, using=None):
        self._set_key()
        super(GroupEhbKey, self).save()

    def __str__(self):
        return self.key
Beispiel #3
0
class UserAudit(CreatedModified):
    """
    This class will store User Audit data to track subject data changes.
    """
    id = models.AutoField(primary_key=True)
    user_name = models.CharField(
        max_length=50, verbose_name='User Name')
    # Change type: SubjectFamRelation, external record, Subject ... should reference a table
    change_type = models.CharField(
        max_length=50, verbose_name='Change type')
    # is not a foreignKey because this could be a PK for many different tables
    change_type_ehb_pk = models.CharField(
        max_length=20, verbose_name='Change Type eHB PK', blank=True)
    # Change Action: create, delete or update
    change_action = models.CharField(
        max_length=50, verbose_name='Change action', blank=True)
    # Change Field: updated field
    change_field = models.CharField(
        max_length=50, verbose_name='Change field', blank=True)
    old_value = EncryptCharField(
        max_length=128, verbose_name='Old Value', blank=True)
    new_value = EncryptCharField(
        max_length=128, verbose_name='New value', blank=True)
    subject = models.ForeignKey(Subject, verbose_name='Subject', on_delete=models.CASCADE)
Beispiel #4
0
class Group(CreatedModified):
    '''
    This class is used as a unique identifier to group related model objects
    such as Subjects and External Records.

    The ehb_key field is randomly generated by the eHB and is guaranteed to be
    unique. Values for ehb_key submitted to
    the API or in a form are ignored.
    '''

    name = EncryptCharField(max_length=255, unique=True, verbose_name='Group Name')
    client_key = models.CharField(max_length=255, verbose_name='Client KEY', editable=True)
    is_locking = models.BooleanField(default=False, verbose_name='Lock Group')
    # this cannot use onetoone because I don't want the ehb_keys to EVER be deleted
    ehb_key = models.ForeignKey(GroupEhbKey, editable=False, blank=True, unique=True, on_delete=models.CASCADE)
    desc_help = 'Please briefly describe this Group.'
    description = models.TextField(verbose_name='Group Description', help_text=desc_help)

    def _create_ehb_key(self):
        '''generate an ehb_key for this Group'''
        # if the key already exists then this model is being edited but this key should not change
        try:
            if self.ehb_key:
                return
        except Exception:
            group_ehb_key = GroupEhbKey()
            group_ehb_key.save()
            self.ehb_key = group_ehb_key

    def ehb_prop(self, GROUP, KEY, default=None):
        EHB_PROPS = settings.EHB_PROPS
        if EHB_PROPS:
            GROUP_SETTINGS = EHB_PROPS.get(GROUP)
            if GROUP_SETTINGS:
                return GROUP_SETTINGS.get(KEY, default)

    def _salt_length(self, default=12):
        return self.ehb_prop('EHB_GROUP_CLIENT_KEYS', 'salt_length', default)

    def _salt_seed(self, default=987654321):
        return self.ehb_prop('EHB_GROUP_CLIENT_KEYS', 'seed', default)

    def _make_salt(self, jump):
        salt_length = self._salt_length()
        seed = self._salt_seed()
        chars = string.ascii_uppercase + string.digits
        random.seed(seed)
        for i in range(jump): dummy = random.random()

        return ''.join(random.choice(chars) for idx in range(salt_length))

    def _hash_value(self, value):
        value = value.encode("utf8")
        h = hashlib.sha256()
        h.update(value)
        return h.hexdigest()

    def verify_client_key(self, other_key):
        if not other_key:
            return False

        b, alg, salt, shpw = self.client_key.split('$')

        return self._hash_value(salt + other_key) == shpw

    def save(self, force_insert=False, force_update=False, using=None):
        self._create_ehb_key()
        jump = self.pk

        if not jump:
            jump = Group.objects.count()
        salt = self._make_salt(jump=jump)
        prefix = '$sha256$' + salt + '$'
        if self.client_key and not self.client_key.startswith(prefix):
            self.client_key = '$sha256$'+salt+'$'+self._hash_value(salt + self.client_key)
        super(Group, self).save()

    class Meta(CreatedModified.Meta):
        ordering = ['name']

    def __str__(self):
        return self.name