class SurveyTicket(Notification): origin = db.ReferenceField(User) survey_unit = db.ListField(db.ReferenceField(SurveyUnit)) def add_comment(self, text, user): if 'comments' not in self.payload: self.payload['comments'] = [] comment_doc = { 'user': user, 'text': text, 'added': datetime.now(), 'id': int(datetime.now().timestamp()) } self.payload['comments'].append(comment_doc) return comment_doc['id'] def resolve(self): self.flagged = False @property def resolved_payload(self): pld = self.payload comments = [] for comment in self.payload.get('comments', []): comments.append({ 'user': comment['user'].repr, 'text': comment['text'], 'added': str(comment['added']), 'id': str(comment['id']), }) pld['comments'] = comments return pld @property def repr(self): doc = { 'id': str(self), 'acquired': str(self.acquired), 'flagged': self.flagged, 'root_survey': self.survey_unit[-1].resolved_root.tiny_repr, 'survey_unit': [_.tiny_repr for _ in self.survey_unit], 'origin': str(self.origin), 'cur_is_orgn': current_user.id == self.origin.id, 'targets': [_.repr for _ in self.destined], 'payload': self.resolved_payload, 'type': self.__class__.__name__, } return doc
class SurveySharePromise(Future): """ Adds the User Credential after they Sign Up. """ future_email = db.StringField(required=True) future_survey = db.ReferenceField(Survey) def routine(self): if not self.active: raise MethodUnavailable() usr = User.objects.get(email = self.future_email) grp = set(self.future_survey.created_by) grp.add(usr) self.future_survey.created_by = list(grp) self.future_survey.save() self.executed = True self.save() return self.repr @property def repr(self): return { 'id': str(self), 'future_email': self.future_email, 'future_survey': self.future_survey.tiny_repr, 'active': self.active, 'executed': self.executed, 'expires': str(self.expires), 'url': self.url, }
class Notification(db.Document): destined = db.ListField(db.ReferenceField(User)) acquired = db.DateTimeField(default=datetime.now) released = db.DateTimeField(default=datetime.max) payload = db.DictField() #: Enables Inheritance. meta = {'allow_inheritance': True} def __unicode__(self): return HashId.encode(self.id) @property def flagged(self): return datetime.now() < self.released @flagged.setter def flagged(self, value): if value is True: self.released = datetime.max else: #: Sets time two seconds behind, to eliminate ANY possibility of # race conditions and prevents other bugs, in general. self.released = datetime.now() - timedelta(seconds=2) @queryset_manager def past(doc_cls, queryset): return queryset.order_by('-acquired') @staticmethod def unflagged_count(): return Notification.past(released__gt=datetime.now()).count()
class Response(db.Document): parent_survey = db.ReferenceField(Survey) metadata = db.DictField() responses = db.DictField() def __unicode__(self): return HashId.encode(self.id) def add(self, qid, qres): if qid in self.parent_survey.cols: self.responses[qid] = qres self.metadata['modified'] = datetime.datetime.now() self.save() else: raise TypeError("Question ID is invalid") if qid in self.parent_survey.notification_hooks: if qres in self.parent_survey.notification_hooks[qid]: survey_response_notify.send(self.parent_survey, response=self, qid=qid, qres=qres) @property def added(self): return self.metadata[ 'started'] if 'started' in self.metadata else datetime.datetime.min
class SurveyResponseNotification(Notification): survey = db.ReferenceField(Survey, required=True) response = db.ReferenceField(Response, required=True) transmit = db.BooleanField(default=False) @property def resolved_payload(self): fields = self.survey.resolved_root.struct.get('fields', []) payload = [] flat_payload = [_ for _ in self.payload] for field in fields: "Look for matching questions, resolve options" "Todo: Resolve Answers " if field.get('cid') in flat_payload: q_field = field.get('field_options', {}).get('options', []) try: res = self.payload.get(field['cid'])[2:].split('###') res_label = [q_field[int(_) - 1].get('label') for _ in res] except Exception: res_label = [""] payload.append({ 'cid': field.get('cid'), 'label': field.get('label'), 'response': self.payload.get(field['cid']), 'res_label': res_label, }) return payload @property def repr(self): doc = { 'id': str(self), 'acquired': str(self.acquired), 'flagged': self.flagged, 'survey': self.survey.tiny_repr, 'root': self.survey.resolved_root.tiny_repr, 'response': str(self.response), 'payload': self.resolved_payload, 'pl': self.payload, 'type': self.__class__.__name__, } return doc
class Attachment(db.Document): added = db.DateTimeField(default=datetime.datetime.now) modified = db.DateTimeField() filename = db.StringField(required=True) owner = db.ReferenceField(User) hidden = db.BooleanField(default=False) meta = {'allow_inheritance': True, 'strict': False} def __unicode__(self): return HashId.encode(self.id) def save(self, **kwargs): self.modified = datetime.datetime.now() super(Attachment, self).save(**kwargs) @queryset_manager def files(doc_cls, queryset): return queryset.filter(hidden=False)
class Connection(db.Document): user_id = db.ReferenceField(User) provider_id = db.StringField() display_name = db.StringField() full_name = db.StringField() secret = db.StringField() email = db.StringField() provider_user_id = db.StringField() profile_url = db.StringField() image_url = db.StringField() access_token = db.StringField() def __unicode__(self): return HashId.encode(self.id) @property def user(self): return User.objects(email=self.user_id.id).first()
class User(db.Document, UserMixin): email = db.EmailField(unique=True, required=True) password = db.StringField(required=True) metadata = db.DictField() active = db.BooleanField(default=True) added = db.DateTimeField(default=datetime.datetime.now) confirmed_at = db.DateTimeField() roles = db.ListField(db.ReferenceField(Role), default=[]) def __unicode__(self): return HashId.encode(self.id) @property def repr(self): doc = { 'id': str(self), 'email': self.email, } return doc
class SurveyUnit(Survey): referenced = db.ReferenceField(Survey, required=True) unit_name = db.StringField() def __init__(self, **kwargs): super(SurveyUnit, self).__init__(**kwargs) if self.referenced: self.structure = self.referenced.structure self.metadata.update(self.referenced.metadata) @property def units(self): "SurveyUnits cannot have Units." return None @property def resolved_root(self): return self.referenced.resolved_root @property def repr(self): return { 'id': str(self), 'unit_name': self.unit_name, 'name': self.metadata['name'], 'is_gamified': self.gamified_enabled, 'uri_simple': '/survey/s:{0}/simple'.format(str(self)), 'uri_game': '/survey/s:{0}/gamified'.format(str(self)), 'uri_edit': '/survey/s:{0}/edit'.format(str(self)), 'uri_responses': '/survey/s:{0}/analysis'.format(str(self)), 'is_paused': self.paused, 'is_active': self.active, 'has_response_cap': self.response_cap, 'has_obtained_responses': self.obtained_responses, 'has_expired': self.expires <= datetime.datetime.now(), 'expires': str(self.expires), 'created_on': str(self.added), 'last_modified': str(self.modified), } @property def repr_sm(self): return { 'id': str(self), 'rootid': str(self.resolved_root), 'meta': { 'name': self.unit_name, 'rootname': self.resolved_root.metadata['name'], 'type': self._cls, }, 'status': { 'paused': self.paused, 'active': self.active, 'response_cap': self.response_cap, 'response_count': self.obtained_responses, 'expired': self.expires <= datetime.datetime.now(), 'unit_count': False, }, 'access': { 'accessible': [_.repr for _ in self.created_by], 'editable': False, #: Unit Survey 'owner': current_user() in self.resolved_root.created_by, }, 'info': { 'expires': str(self.expires), 'added': str(self.added), 'modified': str(self.modified), } } @property def tiny_repr(self): return { 'id': str(self), 'name': self.unit_name, 'active': self.active, } @queryset_manager def objects(doc_cls, queryset): return queryset.filter()
class Survey(db.Document): added = db.DateTimeField(default=datetime.datetime.now) metadata = db.DictField() structure = db.DictField() attachments = db.ListField(db.ReferenceField(AttachmentImage)) created_by = db.ListField(db.ReferenceField(User)) meta = {'allow_inheritance': True, 'strict': False} def __unicode__(self): return HashId.encode(self.id) @property def resolved_root(self): return self @property def cols(self): return [_['cid'] for _ in self.structure['fields']] @property def notification_hooks(self): rules = {} for field in self.structure['fields']: if field.get('notifications', False) is True: options = enumerate(field['field_options'].get('options', [])) store = [] for i, option in options: if option.get('notify', False) is True: store.append("a_{0}".format(i + 1)) rules[field['cid']] = store return rules @property def questions(self): return [[_['cid'], _['label']] for _ in self.structure['fields']] @property def expires(self): return self.metadata[ 'expires'] if 'expires' in self.metadata else datetime.datetime.max @expires.setter def expires(self, value): self.metadata['expires'] = value @property def active(self): time_now = datetime.datetime.now() return all([ not self.hidden, time_now <= self.expires, not self.paused, self.response_cap > self.obtained_responses, ]) @property def paused(self): return self.metadata['paused'] if 'paused' in self.metadata else False @paused.setter def paused(self, value): self.metadata['paused'] = value @property def response_cap(self): return self.metadata[ 'response_cap'] if 'response_cap' in self.metadata else 2**32 @property def obtained_responses(self): return ResponseAggregation(self).count @response_cap.setter def response_cap(self, value): self.metadata['response_cap'] = value @property def struct(self): ret = {} ret['fields'] = self.structure.get('fields', starter_template['fields']) ret['screens'] = self.structure.get('screens', starter_template['screens']) ret['links'] = self.structure.get('links', None) return ret @struct.setter def struct(self, value): try: validate(value, survey_struct_schema) self.structure.update(value) except ValidationError as e: raise TypeError('Struct value invalid' + str(e)) #: DEPRECATED @property def gamified_enabled(self): return False @property def modified(self): return self.metadata[ 'modified'] if 'modified' in self.metadata else self.added @property def img_uploads(self): return [_.repr for _ in self.attachments] @property def hidden(self): return self.metadata['hidden'] if 'hidden' in self.metadata else False @hidden.setter def hidden(self, value): self.metadata['hidden'] = value @property def units(self): dat = SurveyUnit.objects(referenced=self) return [_.repr for _ in dat if not _.hidden] @property def unit_count(self): return SurveyUnit.objects(referenced=self).count() @property def units_as_objects(self): dat = SurveyUnit.objects(referenced=self) return [_ for _ in dat if not _.hidden] def save(self, **kwargs): self.metadata['modified'] = datetime.datetime.now() super(Survey, self).save(**kwargs) @queryset_manager def objects(doc_cls, queryset): return queryset.filter() @queryset_manager def root(doc_cls, queryset): return queryset.filter(_cls='Survey') #: DEPRECATION WARNING: WILL BE CHANGED. @property def repr(self): return { 'id': str(self), 'name': self.metadata['name'], 'is_gamified': self.gamified_enabled, 'uri_simple': '/survey/s:{0}/simple'.format(str(self)), 'uri_game': '/survey/s:{0}/gamified'.format(str(self)), 'uri_edit': '/survey/s:{0}/edit'.format(str(self)), 'uri_responses': '/survey/s:{0}/analysis'.format(str(self)), 'is_paused': self.paused, 'is_active': self.active, 'imgs': self.img_uploads, 'units': self.units, 'has_response_cap': self.response_cap, 'has_obtained_responses': self.obtained_responses, 'has_expired': self.expires <= datetime.datetime.now(), 'expires': str(self.expires), 'created_on': str(self.added), 'last_modified': str(self.modified), } @property def repr_sm(self): return { 'id': str(self), 'meta': { 'name': self.metadata['name'], 'type': self._cls, }, 'status': { 'paused': self.paused, 'active': self.active, 'response_cap': self.response_cap, 'response_count': self.obtained_responses, 'expired': self.expires <= datetime.datetime.now(), 'unit_count': self.unit_count, }, 'access': { 'accessible': [_.repr for _ in self.created_by], 'editable': True, #: Root Survey 'owner': True, }, 'info': { 'expires': str(self.expires), 'added': str(self.added), 'modified': str(self.modified), } } @property def tiny_repr(self): return { 'id': str(self), 'name': self.metadata['name'], 'active': self.active, } #: DEPRECATED @property def render_json(self): #: DEPRECATION WARNING: This method will be removed. rt = {} rt['fields'] = [] rt['game_title'] = "" rt['game_description'] = "" rt['game_footer'] = "" rt['survey_logo'] = "" rt['WARNING'] = "This Feature has been deprecated.\ It will be removed in coming versions.\ This API Call has been preserved for backwards\ compatibility." return rt @property def render_deepjson(self): rt = {} cp = self.struct['fields'] def logic(id_next): return {'va': id_next} for i in range(len(cp)): option_len = len(cp[i]['field_options'].get('options', [])) for j in range(option_len): img = cp[i]['field_options']['options'][j].get('img_uri', None) if img is not None: cp[i]['field_options']['options'][j][ 'img_uri'] = Uploads.url_for_surveyimg(img) cp[i]['next'] = logic('end' if (i + 1) >= len(cp) else cp[i + 1]['cid']) rt['fields'] = cp rt['survey_title'] = self.struct['screens'][0] give_img = len(self.struct['screens']) >= 4 and len( self.struct['screens'][3]) > 1 rt['survey_logo'] = Uploads.url_for_surveyimg( self.struct['screens'][3]) if give_img else False rt['survey_description'] = self.struct['screens'][1] rt['survey_footer'] = self.struct['screens'][2] return rt