class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0018_merge_20170106_1627'),
    ]

    operations = [
        migrations.AlterField(
            model_name='project',
            name='currencies',
            field=multiselectfield.MultiSelectField(choices=[(b'EUR', 'Euro')],
                                                    default=[],
                                                    max_length=100),
        ),
        migrations.AlterField(
            model_name='project',
            name='payout_status',
            field=models.CharField(blank=True,
                                   choices=[(b'needs_approval',
                                             'Needs approval'),
                                            (b'approved', 'Approved'),
                                            (b'created', 'Created'),
                                            (b'in_progress', 'In progress'),
                                            (b'partial', 'Partial'),
                                            (b'success', 'Success'),
                                            (b'failed', 'Failed')],
                                   max_length=50,
                                   null=True),
        ),
    ]
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0071_merge_20180412_1133'),
    ]

    operations = [
        migrations.AddField(
            model_name='projectplatformsettings',
            name='facebook_at_work_url',
            field=models.URLField(max_length=100, null=True),
        ),
        migrations.AddField(
            model_name='projectplatformsettings',
            name='share_options',
            field=multiselectfield.MultiSelectField(choices=[
                (b'twitter', 'Twitter'), (b'facebook', 'Facebook'),
                (b'facebookAtWork', 'Facebook at Work'),
                (b'linkedin', 'LinkedIn'), (b'whatsapp', 'Whatsapp'),
                (b'email', 'Email')
            ],
                                                    default=[],
                                                    max_length=100),
            preserve_default=False,
        ),
    ]
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0077_auto_20180518_1050'),
    ]

    operations = [
        migrations.AlterField(
            model_name='projectplatformsettings',
            name='share_options',
            field=multiselectfield.MultiSelectField(blank=True, choices=[(b'twitter', 'Twitter'), (b'facebook', 'Facebook'), (b'facebookAtWork', 'Facebook at Work'), (b'linkedin', 'LinkedIn'), (b'whatsapp', 'Whatsapp'), (b'email', 'Email')], max_length=100),
        ),
    ]
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0014_auto_20161115_1601'),
    ]

    operations = [
        migrations.AlterField(
            model_name='project',
            name='currencies',
            field=multiselectfield.MultiSelectField(choices=[(b'EUR', 'Euro')], default=[], max_length=100),
        ),
    ]
Esempio n. 5
0
class Reminder(models.Model, model_utils.FieldList):
    REQUIRED = 'r'
    TEXT = 't'
    EMAIL = 'e'
    CALL = 'c'
    COMPLETED = 'o'
    DELETED = 'd'
    FOLLOW_UP_TYPES = (
        (REQUIRED, 'Required'),
        (TEXT, 'Text'),
        (EMAIL, 'Email'),
        (CALL, 'Call'),
        (COMPLETED, 'Completed'),
        (DELETED, 'Deleted'),
    )
    follow_up = multiselectfield.MultiSelectField(choices=FOLLOW_UP_TYPES,
                                                  default=REQUIRED)

    NO_ANSWER = 'n'
    VOICEMAIL = 'v'
    RESULTS = (
        (NO_ANSWER, 'No answer'),
        (VOICEMAIL, 'Voicemail'),
    )
    result = models.CharField(max_length=1, choices=RESULTS, blank=True)

    created = models.DateField()

    class Meta:
        abstract = True

    def get_all_fields(self):
        fields = super().get_all_fields()

        fields.pop('id')  # hide detail/update/delete in generic template

        modal_btn_pseudo = model_utils.FieldList.PseudoBtn('Update')
        modal_btn_pseudo.type = 'modal'
        modal_btn = self.Field(modal_btn_pseudo, '')
        fields.update({'modal_btn': modal_btn})
        fields.move_to_end('modal_btn', last=False)

        new_value = fields['follow_up'].value.replace(' ', '<br />')
        follow_up_pseudo = model_utils.FieldList.PseudoField('Follow up')
        follow_up = self.Field(follow_up_pseudo,
                               safestring.mark_safe(new_value))
        fields.update({'follow_up': follow_up})

        return fields
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0013_merge'),
    ]

    operations = [
        migrations.AlterField(
            model_name='project',
            name='currencies',
            field=multiselectfield.MultiSelectField(choices=[(b'EUR', 'Euro')],
                                                    default=[],
                                                    max_length=100,
                                                    null=True),
        ),
    ]
Esempio n. 7
0
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0047_auto_20171024_1016'),
    ]

    operations = [
        migrations.AddField(
            model_name='projectplatformsettings',
            name='contact_types',
            field=multiselectfield.MultiSelectField(choices=[
                (b'organization', 'Organization'), (b'personal', 'Personal')
            ],
                                                    default=['organization'],
                                                    max_length=100),
            preserve_default=False,
        ),
    ]
Esempio n. 8
0
class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0042_merge_20170920_1332'),
    ]

    operations = [
        migrations.CreateModel(
            name='ProjectPlatformSettings',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('update', models.DateTimeField(auto_now=True)),
                ('project_create_types', multiselectfield.MultiSelectField(choices=[(b'sourcing', 'Sourcing'), (b'funding', 'Funding')], max_length=100)),
                ('project_create_flow', models.CharField(choices=[(b'combined', 'Combined'), (b'choice', 'Choice')], max_length=100)),
                ('project_suggestions', models.BooleanField(default=True)),
                ('project_contact_method', models.CharField(choices=[(b'mail', 'E-mail'), (b'phone', 'Choose')], max_length=100)),
            ],
            options={
                'verbose_name': 'Project Settings',
                'verbose_name_plural': 'Project Settings',
            },
        ),
        migrations.CreateModel(
            name='ProjectSearchFilter',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(choices=[(b'location', 'Location'), (b'theme', 'Theme'), (b'skill', 'Skill'), (b'date', 'Date'), (b'status', 'Status'), (b'type', 'Type')], max_length=100)),
                ('default', models.CharField(blank=True, max_length=100, null=True)),
                ('values', models.CharField(blank=True, help_text='Comma separated list of possible values', max_length=500, null=True)),
            ],
        ),
        migrations.AddField(
            model_name='projectplatformsettings',
            name='search_filters',
            field=models.ManyToManyField(to='projects.ProjectSearchFilter'),
        ),
    ]
Esempio n. 9
0
class StudyAction(models.Model):
    """
    A model for the data that we're saving in CSV form in production. We
    translate the data there into a database model that we can then use for
    data processing however we wish to.

    This should never be populated with the `dropbox_to_db` and `db_to_dropbox`
    scripts. Instead, prefer the use of another script that converts CSV data
    into rows amenable to this model
    """

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    start_timestamp = models.DateTimeField(
    )  # This is the timestamp one row above in the CSV
    end_timestamp = models.DateTimeField(
    )  # This is the timestamp on the same row

    start_state = models.CharField(max_length=80)
    diagnoses = multiselectfield.MultiSelectField(
        choices=tuple(constants.DIAGNOSES.items()))
    diagnosis_certainty = models.IntegerField()
    action = models.CharField(max_length=20,
                              choices=tuple(constants.ACTIONS.items()))
    next_state = models.CharField(max_length=80, null=True, blank=True)

    video_loaded_time = models.DateTimeField()
    video_stop_time = models.DateTimeField()
    dx_selected_time = models.DateTimeField()
    dx_confirmed_time = models.DateTimeField()
    ax_selected_time = models.DateTimeField()

    # Other data not part of the JSON action information
    browser_refreshed = models.BooleanField(default=False)
    corrupted_dx_suggestions = models.BooleanField(default=False)
    corrupted_ax_suggestions = models.BooleanField(default=False)
    dx_suggestions = multiselectfield.MultiSelectField(choices=tuple(
        constants.DIAGNOSES.items()),
                                                       blank=True,
                                                       null=True)
    ax_suggestions = multiselectfield.MultiSelectField(choices=tuple(
        constants.ACTIONS.items()),
                                                       blank=True,
                                                       null=True)

    # Cached property
    _action_idx = None

    # Fields that should not be part of the JSON action information
    NOT_CSV_HEADER_FIELDS = [
        'id',
        'user',
        'start_timestamp',
        'end_timestamp',
        'browser_refreshed',
        'dx_suggestions',
        'ax_suggestions',
        # The corrupted flags should be populated post-processing, but they
        # are now forever part of the CSV header
    ]

    class Meta:
        verbose_name = _('study action')
        verbose_name_plural = _('study actions')

    def __str__(self):
        return f"{self.user.username}, {self.action_idx}"

    @staticmethod
    def get_csv_headers():
        """
        Headers corresponding to the fields that should be present in the CSV.
        The returned value is used by the `utils` code to figure out how to
        structure the CSV
        """
        return [
            x.name for x in StudyAction._meta.get_fields()
            if x.name not in StudyAction.NOT_CSV_HEADER_FIELDS
        ]

    @property
    def action_idx(self):
        """Get the action index for the given user"""
        if self._action_idx is None:
            self._action_idx = StudyAction.objects.filter(
                user=self.user,
                start_timestamp__lt=self.start_timestamp).count()

        return self._action_idx

    @property
    def duration(self):
        return (
            self.end_timestamp -
            self.start_timestamp) if self.start_timestamp is not None else None

    @property
    def dx_decision_duration(self):
        return (
            self.dx_selected_time -
            self.video_stop_time) if self.video_stop_time is not None else None

    @property
    def ax_decision_duration(self):
        return (self.ax_selected_time - self.dx_confirmed_time
                ) if self.dx_confirmed_time is not None else None

    @property
    def decision_duration(self):
        return (
            self.ax_selected_time -
            self.video_stop_time) if self.video_stop_time is not None else None

    @property
    def chose_dx_suggestion(self):
        if self.diagnoses is None or self.dx_suggestions is None:
            return None
        return len(set(self.diagnoses) & set(self.dx_suggestions)) > 0

    @property
    def chose_ax_suggestion(self):
        # None of the data will hit this. So instead we return 0 (not NA) when
        # there are no AX suggestions
        if self.action is None or self.ax_suggestions is None:
            return None
        return self.action in self.ax_suggestions

    @property
    def chose_dx_optimal(self):
        if self.start_state is None or self.diagnoses is None:
            return None
        state = State(eval(self.start_state))
        optimal_dx = Suggestions().ordered_diagnoses(state,
                                                     None,
                                                     accumulate=True)
        return len(set(self.diagnoses) & set(optimal_dx)) > 0

    @property
    def chose_ax_optimal(self):
        if self.start_state is None or self.action is None:
            return None
        state = State(eval(self.start_state))
        optimal_ax = Suggestions().optimal_action(state, None)
        return self.action in optimal_ax
Esempio n. 10
0
class Service(models.Model):
    METHOD_CHOICES = (
        (u'delete', u'delete'),
        (u'get', u'get'),
        (u'post', u'post'),
        (u'patch', u'patch'),
        (u'put', u'put'),
    )
    codes = sorted(
        list(
            set([
                a if isinstance(a, int) else 100
                for a in requests.codes.__dict__.values()
            ])))
    ACCEPTED_CODE_CHOICES = []
    for code in codes:
        if code >= 400:
            ACCEPTED_CODE_CHOICES.append((code, code))
    REJECTED_CODE_CHOICES = []
    for code in codes:
        if code < 400:
            REJECTED_CODE_CHOICES.append((code, code))

    name = models.CharField(max_length=200, default='', db_index=True)
    url = models.URLField(max_length=200, default='')
    method = models.CharField(max_length=20,
                              choices=METHOD_CHOICES,
                              default='get')
    timeout = models.IntegerField(blank=True, null=True, default=None)
    verify = models.BooleanField(default=True)
    headers = models.TextField(blank=True, default='')
    parameters = models.TextField(blank=True, default='')
    service_failover = models.ManyToManyField(
        "self",
        through='ServiceFailover',
        symmetrical=False,
        related_name='service_failover_relation')
    accepted_codes = multiselectfield.MultiSelectField(
        choices=ACCEPTED_CODE_CHOICES, blank=True, default=None)
    rejected_codes = multiselectfield.MultiSelectField(
        choices=REJECTED_CODE_CHOICES, blank=True, default=None)

    def __str__(self):
        return self.name

    def accept_code(self, code):
        res = True
        if code < 400 and str(code) in self.rejected_codes:
            res = False
        elif code >= 400 and str(code) not in self.accepted_codes:
            res = False
        return res

    async def request_async_task(self,
                                 max_retry=10,
                                 retry_interval=1,
                                 header_data=None,
                                 get_data=None,
                                 url_data=None,
                                 parse_data=None,
                                 parameters=None):
        service_response = self.request_recursive(header_data=header_data,
                                                  get_data=get_data,
                                                  url_data=url_data,
                                                  parse_data=parse_data,
                                                  parameters=parameters)
        current_try = 1
        while not service_response['success'] and (max_retry == 0
                                                   or max_retry < current_try):
            time.sleep(retry_interval)
            if max_retry != 0:
                current_try += 1
            service_response = self.request_recursive(header_data=header_data,
                                                      get_data=get_data,
                                                      url_data=url_data,
                                                      parse_data=parse_data,
                                                      parameters=parameters)

    def request_async(self,
                      max_retry=10,
                      retry_interval=1,
                      header_data=None,
                      get_data=None,
                      url_data=None,
                      parse_data=None,
                      parameters=None):

        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop = asyncio.get_event_loop()
        loop.run_until_complete(
            self.request_async_task(max_retry=max_retry,
                                    retry_interval=retry_interval,
                                    header_data=header_data,
                                    get_data=get_data,
                                    url_data=url_data,
                                    parse_data=parse_data,
                                    parameters=parameters))
        loop.close()

    def request_recursive(self,
                          header_data=None,
                          get_data=None,
                          url_data=None,
                          parse_data=None,
                          parameters=None):
        response = self.request(header_data=header_data,
                                get_data=get_data,
                                url_data=url_data,
                                parameters=parameters)
        if response.get('result') == 'OK':
            return response
        elif self.pk and self.service_failover.count() != 0:
            response_failover_stack = []
            for service_for_failover in self.service_failover.all():
                response_failover, result_failover = service_for_failover.get_service_data(
                    header_data=header_data,
                    get_data=get_data,
                    url_data=url_data,
                    parse_data=parse_data,
                    parameters=parameters)
                if response_failover.get('result') == 'OK':
                    return response_failover, result_failover
                response_failover_stack.append(response_failover)
            response.update({'failovers': response_failover_stack})
        return response

    def request(self,
                header_data=None,
                get_data=None,
                url_data=None,
                parameters=None):
        headers = {}

        service_headers = self.headers

        if service_headers:
            headers = json.loads(service_headers)
            for headers_key in headers:
                if header_data and headers[headers_key] and headers[
                        headers_key] in header_data:
                    headers[headers_key] = header_data[headers[headers_key]]

        data = {}
        service_parameters = self.parameters

        if service_parameters:
            data = json.loads(service_parameters)
            for data_key in data:
                if data[data_key] and get_data and data[data_key] in get_data:
                    data[data_key] = get_data[data[data_key]]
        elif parameters:
            data = parameters

        service_url = self.url

        if url_data:
            for url_data_key in url_data:
                service_url = service_url.replace(url_data_key,
                                                  url_data[url_data_key])

        response = self.get_from_service(service_url, headers, data)

        return response

    def get_from_service(self, url, headers, data):
        if self.timeout:
            timeout = self.timeout
        else:
            timeout = 10
        try:
            if self.method == 'post':
                result = requests.post(url,
                                       data=json.dumps(data),
                                       headers=headers,
                                       timeout=timeout,
                                       verify=self.verify)
            elif self.method == 'get':
                data = urllib.parse.urlencode(data)
                if data:
                    url = url + '?' + data
                result = requests.get(url,
                                      headers=headers,
                                      timeout=timeout,
                                      verify=self.verify)
            elif self.method == 'patch':
                result = requests.patch(url,
                                        data=json.dumps(data),
                                        headers=headers,
                                        timeout=timeout,
                                        verify=self.verify)
            elif self.method == 'put':
                result = requests.put(url,
                                      data=json.dumps(data),
                                      headers=headers,
                                      timeout=timeout,
                                      verify=self.verify)
            elif self.method == 'delete':
                data = urllib.parse.urlencode(data)
                if data:
                    url = url + '?' + data
                result = requests.delete(url,
                                         headers=headers,
                                         timeout=timeout,
                                         verify=self.verify)
            try:
                response = result.json()
            except:
                response = {}
            if not self.accept_code(result.status_code):
                response = {
                    "result":
                    "error",
                    "success":
                    False,
                    "content":
                    response,
                    "code":
                    result.status_code,
                    "elapsed":
                    result.elapsed.seconds +
                    result.elapsed.microseconds / 1000000.0
                }
            else:
                response = {
                    "result":
                    "ok",
                    "success":
                    True,
                    "content":
                    response,
                    "code":
                    result.status_code,
                    "elapsed":
                    result.elapsed.seconds +
                    result.elapsed.microseconds / 1000000.0
                }

        except requests.exceptions.Timeout:
            response = {
                "result": "error",
                "success": False,
                "content": 'service timeout',
                "elapsed": timeout,
                "code": 408
            }
        except requests.exceptions.ConnectionError:
            response = {
                "result": "error",
                "success": False,
                "content": 'connection error',
                "code": 503
            }
        return response