def user_profile_view(self): if not self.request.matchdict["user_id"] in self.request.root.users: self.request.session.flash("Requested user does not exist!", "error") return HTTPFound(location=self.request.route_path("admin_accounts")) user = self.request.root.users[self.request.matchdict["user_id"]] if "action" in self.request.GET: if self.request.GET["action"] == "counttotal": user.total_tickets = len(user.tickets) self.request.session.flash("Recounted the total number of tickets this user has.", "info") elif self.request.GET["action"] == "sendtickets": emailer = GenericEmail(self.request) emailer.compose_and_send( "Event Tickets", """Please find the tickets you have purchased attached as a PDF to this email. Please download and print-out the tickets and bring them with you to the event.""", user.__name__, pdf_attachment=TicketDownload(self.request).user_tickets_pdf(user) ) self.request.session.flash("All tickets have been sent to this user via email.", "info") if user.profile == None: self.request.session.flash("Requested user had not setup a profile, now has a blank profile.", "info") user.profile = UserProfile() user.profile.__parent__ = user return { "chosen_user": user }
def edit_profile_view(self): # Check agreements if not self.user.purchase_agreement: return HTTPFound(location=self.request.route_path("purchase_agreement_act")) elif not self.user.privacy_agreement: return HTTPFound(location=self.request.route_path("privacy_policy_act")) # Check if the user is allowed to edit their profile if self.account_lock_down: self.request.session.flash("Account details have been locked down, therefore editing is disabled.", "error") return HTTPFound(location=self.request.route_path("user_profile")) user = self.user if user.profile == None: user.profile = UserProfile() user.profile.__parent__ = user profile = user.profile # Grab the address lineone = linetwo = city = county = country = postal_code = None address = profile.address if address != None: lineone = address.line_one linetwo = address.line_two city = address.city county = address.county country = address.country postal_code = address.postal_code # Sort out DOB dob_year = dob_month = dob_day = None if profile.dob != None: dob_year = profile.dob.year dob_month = profile.dob.month dob_day = profile.dob.day # Process into the profile return { "title": profile.title, "othertitle": (profile.title not in ["Mr", "Mrs", "Miss", "Ms", "Dr", "Prof", "Rev"] and len(profile.title) > 0), "forename": profile.forename, "surname": profile.surname, "email": profile.email, "phone_number": profile.phone_number, "dob_year": dob_year, "dob_month": dob_month, "dob_day": dob_day, "crsid": profile.crsid, "college": profile.college, "grad_status": profile.grad_status, # Address stuff "lineone": lineone, "linetwo": linetwo, "city": city, "county": county, "country": country, "postal_code": postal_code, }
def welcome_view_do(self): if not self.has_queued: return HTTPFound(location=self.request.route_path("queue")) # Get username and password username = self.request.POST["username"].lower() password = self.request.POST["password"] # Check if user exists and is non-raven if not username in self.request.root.users: self.request.session.flash( "Your username or password was incorrect", "error") return HTTPFound(location=self.request.route_path("welcome")) user = self.request.root.users[username] if user.profile != None and user.profile.raven_user: self.request.session.flash( "Your account appears to be a Raven account, please use the Raven login instead.", "error") return HTTPFound(location=self.request.route_path("welcome")) # Check password if user.password != salt_password(password, user.password_salt): self.request.session.flash( "Your username or password was incorrect", "error") return HTTPFound(location=self.request.route_path("welcome")) # Ok, this all looks ok - lets go! header = remember(self.request, user.__name__) self.request.session["user_id"] = user.__name__ if user.profile == None: profile = UserProfile() profile.raven_user = False profile.__parent__ = user profile.__name__ = user.__name__ + "-profile" user.profile = profile return HTTPFound( location=self.request.route_path('user_profile_edit'), headers=header) elif None in [user.profile.dob, user.profile.fullname]: return HTTPFound( location=self.request.route_path('user_profile_edit'), headers=header) else: return HTTPFound(location=self.request.route_path('user_profile'), headers=header)
def signup_view(self): if not self.public_signup_enabled: self.request.session.flash( "Public sign-ups are not currently enabled!", "error") return HTTPFound(location=self.request.route_path('welcome')) # If form data submitted if "submit" in self.request.POST: email = (self.request.POST["email"] if "email" in self.request.POST and len(self.request.POST["email"]) > 0 else None) username = (self.request.POST["username"] if "username" in self.request.POST and len(self.request.POST["username"]) > 0 else None) pwd_one = (self.request.POST["password"] if "password" in self.request.POST and len(self.request.POST["password"]) > 0 else None) pwd_two = (self.request.POST["confirm_password"] if "confirm_password" in self.request.POST and len(self.request.POST["confirm_password"]) > 0 else None) discount_code = (self.request.POST["discount_code"] if "discount_code" in self.request.POST and len(self.request.POST["discount_code"]) > 0 else None) # Check if all fields filled if email == None or username == None or pwd_one == None or pwd_two == None: self.request.session.flash( "One or more fields was not filled, please try again.", "error") return { "email": email, "username": username, "discount_code": discount_code } # Now run additional checks validator = Email() if not validator(email): self.request.session.flash( "Please enter a valid email address.", "error") return { "email": email, "username": username, "discount_code": discount_code } # Username checks username = username.lower() if len(username) < 3 or " " in username: self.request.session.flash( "Please enter a valid username of more than 3 characters and containing no spaces.", "error") return { "email": email, "username": username, "discount_code": discount_code } if username in self.request.root.users or (re.match( r"^[a-zA-Z]+[0-9]+$", username) != None): self.request.session.flash( "A user already exists with the username you specified, please try again.", "error") return { "email": email, "username": username, "discount_code": discount_code } # Password checks if pwd_one != pwd_two: self.request.session.flash( "Your passwords do not appear to match, please try again.", "error") return { "email": email, "username": username, "discount_code": discount_code } if len(pwd_one) < 5 or (re.match(r"(?=.{6,}).*", pwd_one) == None): self.request.session.flash( "Your password is too short or not complex enough, please enter a stronger password.", "error") return { "email": email, "username": username, "discount_code": discount_code } # Passed all checks - create an account... group = self.request.root.groups['ungrouped'] # - See if we can find a discount group if discount_code != None: found_discount = False for group_key in self.request.root.groups: test_group = self.request.root.groups[group_key] if test_group.access_code != None and len( test_group.access_code ) > 0 and test_group.access_code == discount_code: group = test_group found_discount = True break if not found_discount: self.request.session.flash( "The discount code entered is not valid, please check it and try again.", "error") return { "email": email, "username": username, "discount_code": discount_code } # - Now setup user user = User() user.username = user.__name__ = username user.password_salt = Coding().generateUniqueCode() user.password = salt_password(pwd_one, user.password_salt) user.profile = UserProfile() user.profile.__parent__ = user user.profile.raven_user = False user.profile.email = email user.__parent__ = group group.members.append(user) self.request.root.users[user.__name__] = user # ...send an email telling them about their new account... emailer = GenericEmail(self.request) emailer.compose_and_send( "Account Created", """Thank you for creating an account on our ticketing system, this email is just to remind you that your username is %s. No further action is required.""" % (user.username), user.__name__) # ...and finally login header = remember(self.request, user.__name__) self.request.session["user_id"] = user.__name__ return HTTPFound( location=self.request.route_path('user_profile_edit'), headers=header) return {"email": None, "username": None, "discount_code": None}
def db_setup_accounts(self, root): # Groups & users root.groups = PersistentMapping() root.users = PersistentMapping() # admin admin = Group() admin.__name__ = "admin" admin.__parent__ = root admin.can_delete = False admin.name = "Administrators" admin.privileges = ["admin"] admin.can_delete = False admin._p_changed = True root.groups[admin.__name__] = admin # committee committee = Group() committee.__name__ = "committee" committee.__parent__ = root committee.name = "Committee Members" committee.privileges = ["committee"] committee.can_delete = False committee._p_changed = True root.groups[committee.__name__] = committee # Raven authentications raven_grp = Group() raven_grp.__name__ = "raven" raven_grp.__parent__ = root raven_grp.name = "Customers (Raven)" raven_grp.privileges = ["basic"] raven_grp.can_delete = False raven_grp._p_changed = True root.groups[raven_grp.__name__] = raven_grp # Alumnus Raven authentications alumni_raven_grp = Group() alumni_raven_grp.__name__ = "raven_alumni" alumni_raven_grp.__parent__ = root alumni_raven_grp.name = "Customers (Alumni via Raven)" alumni_raven_grp.privileges = ["basic"] alumni_raven_grp.can_delete = False alumni_raven_grp._p_changed = True root.groups[alumni_raven_grp.__name__] = alumni_raven_grp # Alumnus authentications alumni_grp = Group() alumni_grp.__name__ = "alumni" alumni_grp.__parent__ = root alumni_grp.name = "Customers (Alumni)" alumni_grp.privileges = ["basic"] alumni_grp.can_delete = False alumni_grp._p_changed = True root.groups[alumni_grp.__name__] = alumni_grp # Ungrouped ungrouped = Group() ungrouped.__name__ = "ungrouped" ungrouped.__parent__ = root ungrouped.name = "Ungrouped" ungrouped.privileges = ["basic"] ungrouped.can_delete = False ungrouped._p_changed = True root.groups[ungrouped.__name__] = ungrouped # Setup an admin user admin_usr = User() admin_usr.username = "******" admin_usr.password_salt = Coding().generateUniqueCode() admin_usr.password = salt_password("password", admin_usr.password_salt) admin_usr.__name__ = admin_usr.username admin_usr.__parent__ = admin root.users[admin_usr.__name__] = admin_usr admin.members.append(admin_usr) admin.members._p_changed = True admin_usr.privacy_agreement = True admin_usr.purchase_agreement = True admin_prof = UserProfile() admin_usr.profile = admin_prof admin_prof.__parent__ = admin_usr admin_prof.title = "Admin" admin_prof.forename = "Super" admin_prof.surname = "Administrator" admin_prof.email = "*****@*****.**" admin_prof.dob = datetime(year=1990, month=1, day=1) admin_prof.photo_file = "blank.png" admin_prof.address = PostalAddress() admin_prof.address.__parent__ = admin_prof admin_prof.address.line_one = "Admin Address" admin_prof.address.line_two = "Admin Address" admin_prof.address.city = "Cambridge" admin_prof.address.county = "Cambridgeshire" admin_prof.address.country = "United Kingdom" admin_prof.address.postal_code = "CB1 1AA" admin_prof.phone_number = "01234 567890"
def edit_profile_view_do(self): # Check agreements if not self.user.purchase_agreement: return HTTPFound(location=self.request.route_path("purchase_agreement_act")) elif not self.user.privacy_agreement: return HTTPFound(location=self.request.route_path("privacy_policy_act")) # Check if the user is allowed to edit their profile if self.account_lock_down: self.request.session.flash("Account details have been locked down, therefore editing is disabled.", "error") return HTTPFound(location=self.request.route_path("user_profile")) user = self.user if user.profile == None: user.profile = UserProfile() user.profile.__parent__ = user if not user.profile.raven_user and user.profile.address == None: user.profile.address = PostalAddress() user.profile.address.__parent__ = user.profile profile = user.profile # Ok - process the form and validate all details processor = ProcessAndValidate( self.request.POST, self.request.registry._settings["base_dir"], PROP_KEYS.getProperty(self.request, PROP_KEYS.MINIMUM_AGE), PROP_KEYS.getProperty(self.request, PROP_KEYS.EVENT_DATE), profile=profile, photo_required=PROP_KEYS.getProperty(self.request, PROP_KEYS.PHOTO_REQUIRED)) try: data = processor.process() # Save profile details profile.title = data["title"] profile.forename = data["forename"] profile.surname = data["surname"] if not profile.raven_user: profile.crsid = data["crsid"] if profile.raven_user and profile.raven_alumnus != True: profile.email = profile.crsid + "@cam.ac.uk" else: profile.email = data["email"] profile.phone_number = data["phone_number"] profile.photo_file = data["photofile"] profile.dob = data["dob"] profile.college = data["college"] profile.grad_status = data["grad_status"] if self.user.profile == profile and (profile.raven_user == False or profile.raven_alumnus == True): if profile.address == None: profile.address = PostalAddress() profile.address.__parent__ = user.profile profile.address.line_one = self.request.POST["lineone"] if len(profile.address.line_one) < 4: raise ValueError("You must provide a full and valid address.") profile.address.line_two = self.request.POST["linetwo"] profile.address.city = self.request.POST["city"] if len(profile.address.city) < 2: raise ValueError("You must enter a town or city.") profile.address.county = self.request.POST["county"] if not "country" in self.request.POST or len(self.request.POST["country"]) < 4: raise ValueError("You must select a country of residence.") profile.address.country = self.request.POST["country"] profile.address.postal_code = self.request.POST["postal_code"] if len(profile.address.postal_code) < 4: raise ValueError("You must provide a postal or zip code.") profile._p_changed = True except ValueError, e: logging.error("%s: Received a value error when processing profile: %s" % (self.user.username, e)) message = str(e) self.request.session.flash(message, "error") title = self.request.POST["title"] if "title" in self.request.POST else "" if title == "Other": title = self.request.POST["othertitle"] forename = self.request.POST["forename"] surname = self.request.POST["surname"] email = None phone_number = self.request.POST["phone_number"] dob_year = self.request.POST["dob_year"] dob_month = self.request.POST["dob_month"] dob_day = self.request.POST["dob_day"] crsid = None college = None grad_status = None lineone = linetwo = city = county = country = postal_code = None # Optionally fill in postal details if self.user.profile == profile and (profile.raven_alumnus == True or profile.raven_user == False): lineone = self.request.POST["lineone"] linetwo = self.request.POST["linetwo"] city = self.request.POST["city"] county = self.request.POST["county"] if "country" in self.request.POST: country = self.request.POST["country"] postal_code = self.request.POST["postal_code"] if profile.raven_user == False or profile.raven_alumnus == True: email = self.request.POST["email"] elif profile.raven_user == True and profile.raven_alumnus == False: email = profile.crsid.replace(" ","") + "@cam.ac.uk" if profile.raven_user == True: crsid = profile.crsid college = self.request.POST["college"] grad_status = self.request.POST["grad_status"] return { "title": title, "othertitle": (title != None and title not in ["Mr", "Mrs", "Miss", "Ms", "Dr", "Prof", "Rev"] and len(title) > 0), "forename": forename, "surname": surname, "email": email, "phone_number": phone_number, "dob_year": dob_year, "dob_month": dob_month, "dob_day": dob_day, "crsid": crsid, "college": college, "grad_status": grad_status, # Address stuff "lineone": lineone, "linetwo": linetwo, "city": city, "county": county, "country": country, "postal_code": postal_code, }
def user_profile_edit_view(self): if not self.request.matchdict["user_id"] in self.request.root.users: self.request.session.flash("Requested user does not exist!", "error") return HTTPFound(location=self.request.route_path("admin_accounts")) user = self.request.root.users[self.request.matchdict["user_id"]] if "submit" in self.request.POST: problem = False user.profile.title = self.request.POST["title"] if user.profile.title == "Other": user.profile.title = self.request.POST["othertitle"] user.profile.forename = self.request.POST["forename"] user.profile.surname = self.request.POST["surname"] if "email" in self.request.POST: user.profile.email = self.request.POST["email"] user.profile.phone_number = self.request.POST["phone_number"] day = int(float(self.request.POST["dob_day"])) month = int(float(self.request.POST["dob_month"])) year = int(float(self.request.POST["dob_year"])) if day < 1 or day > 31 or month < 1 or month > 12: problem = True self.request.session.flash("Invalid date of birth, please try again", "error") dob = datetime(year, month, day) event_date = PROP_KEYS.getProperty(self.request, PROP_KEYS.EVENT_DATE) minimum_age = PROP_KEYS.getProperty(self.request, PROP_KEYS.MINIMUM_AGE) if relativedelta(event_date, dob).years < minimum_age: problem = True self.request.session.flash("Guests must be aged %i on the day of the event, age entered is too young." % minimum_age, "error") if not problem: user.profile.dob = dob user.profile.raven_user = ("atcambridge" in self.request.POST and self.request.POST["atcambridge"] == "yes") if user.profile.raven_user: user.profile.crsid = self.request.POST["crsid"] user.profile.email = user.profile.crsid + "@cam.ac.uk" user.profile.college = self.request.POST["college"] user.profile.grad_status = self.request.POST["grad_status"] else: if user.profile.address == None: user.profile.address = PostalAddress() user.profile.address.__parent__ = user user.profile.address.line_one = self.request.POST["lineone"] user.profile.address.line_two = self.request.POST["linetwo"] user.profile.address.city = self.request.POST["city"] user.profile.address.county = self.request.POST["county"] user.profile.address.country = self.request.POST["country"] user.profile.address.postal_code = self.request.POST["postal_code"] return HTTPFound(location=self.request.route_path("admin_view_user", user_id=user.__name__)) if user.profile == None: user.profile = UserProfile() user.profile.__parent__ = user info = user.profile dob = datetime.now() if info.dob != None: dob = info.dob # Address lineone = linetwo = city = county = country = postal_code = "" if info.address != None: lineone = info.address.line_one linetwo = info.address.line_two city = info.address.city county = info.address.county country = info.address.country postal_code = info.address.postal_code return { "user_id": user.__name__, "title": info.title, "othertitle": (info.title not in ["Mr", "Mrs", "Miss", "Ms", "Dr", "Prof", "Rev"] and len(info.title) > 0), "forename": info.forename, "surname": info.surname, "phone_number": info.phone_number, "email": info.email, "dob_year": dob.year, "dob_month": dob.month, "dob_day": dob.day, "atcambridge": info.raven_user, "crsid": info.crsid, "college": info.college, "grad_status": info.grad_status, "needs_address": (info.raven_user == False), "lineone": lineone, "linetwo": linetwo, "city": city, "county": county, "country": country, "postal_code": postal_code, }
def allocate_tickets_view(self): if "submit" in self.request.POST: username = self.request.POST["username"].lower() if not username in self.request.root.users: self.request.session.flash( "The user you specified does not exist, ticket allocation failed.", "error") return {} user = self.request.root.users[username] num_tickets = int(float(self.request.POST["numtickets"])) if num_tickets <= 0: self.request.session.flash( "You must specify a number of tickets to issue, allocation failed.", "error") # Build the list of requested tickets and addons tick_types = {} for i in range(0, num_tickets): type_code = self.request.POST["ticket-%i-type" % i] addon_code = self.request.POST["ticket-%i-addon" % i] if type_code in tick_types: tick_types[type_code]["count"] += 1 if addon_code in tick_types[type_code]["addons"]: tick_types[type_code]["addons"][addon_code] += 1 else: tick_types[type_code]["addons"][addon_code] = 1 else: tick_types[type_code] = { "count": 1, "addons": { addon_code: 1 } } # Check stock of tickets and addons for type_key in tick_types: number = tick_types[type_key]["count"] addons = tick_types[type_key]["addons"] if not type_key in self.request.root.ticket_pools: self.request.session.flash( "Invalid ticket type was specified.", "error") return {} pool = self.request.root.ticket_pools[type_key] if len(pool.tickets) < number: self.request.session.flash( "There is not enough stock of '%s' to allocate the requested tickets." % pool.tick_type.name, "error") return {} #if not user.__parent__.__name__ in pool.groups: # self.request.session.flash("The user is not permitted to have tickets of the type '%s'." % pool.tick_type.name, "error") # return {} # Now check addons for addon_key in addons: if addon_key == "none": continue if not addon_key in pool.tick_type.addons: self.request.session.flash( "Invalid addon type was specified.", "error") return {} addon = pool.tick_type.addons[addon_key] num_addons = addons[addon_key] if addon.remaining < num_addons: self.request.session.flash( "There is not enough stock of the addon '%s' to allocate the requested tickets." % addon.name, "error") return {} # Issue the tickets and attach all addons requested has_ticket = (user.tickets != None and len(user.tickets) > 0 ) # Whether we need to set a ticket to be theirs all_tickets = [] for type_key in tick_types: number = tick_types[type_key]["count"] addons = tick_types[type_key]["addons"] pool = self.request.root.ticket_pools[type_key] for i in range(0, number): ticket = pool.tickets[0] user.tickets.append(ticket) pool.tickets.remove(ticket) ticket.__parent__ = user ticket.owner = user ticket.issue_date = datetime.now() ticket.change_enabled = True # Allow user to update guest details once if not has_ticket: ticket.guest_info = user.profile has_ticket = True else: blank_profile = UserProfile() blank_profile.__parent__ = ticket ticket.guest_info = blank_profile all_tickets.append(ticket) # Attach an addon if available for addon_key in addons: if addon_key == "none" or addons[addon_key] <= 0: continue addon = pool.tick_type.addons[addon_key] ticket.addons[addon.__name__] = addon addon.allocated.append(ticket) addons[addon_key] -= 1 break # Open a payment and attach all of the tickets into it gift = ("gift" in self.request.POST and self.request.POST["gift"] == "gift") payment = Payment() payment.owner = user payment.__parent__ = user payment.opened_date = datetime.now() for ticket in all_tickets: ticket.payment = payment payment.tickets.append(ticket) if gift: new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "gifted" new_stage.amount_paid = int(payment.amount_remaining) new_stage.processing_charge = 0 new_stage.received = new_stage.cashed = True new_stage.completed = True new_stage.stage_owner = user.__name__ payment.history.append(new_stage) payment.completed_date = datetime.now() else: new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "cheque" new_stage.method_change = True new_stage.stage_owner = user.__name__ payment.history.append(new_stage) # Attach the payment to the user user.payments.append(payment) user.total_tickets += len(payment.tickets) self.request.root.payments[payment.__name__] = payment # Send a information email if user.profile != None: emailer = GenericEmail(self.request) if gift: emailer.compose_and_send( "Tickets Allocated", """This is to notify you that %i ticket(s) have been allocated to your account, they have been transferred as a gift and hence no further action is required. If you want to get in touch, your ticket allocation reference is %s.""" % (len(payment.tickets), payment.ref_code), payment.owner.__name__) else: emailer.compose_and_send( "Tickets Allocated", """This is to notify you that %i ticket(s) have been allocated to your account. You are required to complete payment for your tickets, currently they are set as a default of cheque payment, however you may change this by logging into your ticket account. Your purchase reference is %s and your owed total is %s.""" % (len(payment.tickets), payment.ref_code, self.format_price(payment.total)), payment.owner.__name__) # Report all good self.request.session.flash("Ticket allocation successful!", "info") return HTTPFound(location=self.request.route_path("admin_tickets")) return {}
def ticket_guest_profile_edit_view(self): ticket = None if "ticket_id" in self.request.matchdict: users = self.request.root.users.values() for user in users: for tick in user.tickets: if tick.id_code == self.request.matchdict["ticket_id"]: ticket = tick break if ticket != None: break else: return HTTPFound(location=self.request.route_path("admin_tickets")) # Check we actually got something if ticket == None: return HTTPFound(location=self.request.route_path("admin_tickets")) # Check owner is not the guest if ticket.guest_info == ticket.owner.profile: return HTTPFound(location=self.request.route_path( "admin_user_profile_edit", user_id=ticket.owner.__name__)) if "submit" in self.request.POST: ticket.guest_info.title = self.request.POST["title"] if ticket.guest_info.title == "Other": ticket.guest_info.title = self.request.POST["othertitle"] ticket.guest_info.forename = self.request.POST["forename"] ticket.guest_info.surname = self.request.POST["surname"] if "email" in self.request.POST: ticket.guest_info.email = self.request.POST["email"] day = int(float(self.request.POST["dob_day"])) month = int(float(self.request.POST["dob_month"])) year = int(float(self.request.POST["dob_year"])) problem = False if day < 1 or day > 31 or month < 1 or month > 12: problem = True self.request.session.flash( "Invalid date of birth, please try again", "error") dob = datetime(year, month, day) event_date = PROP_KEYS.getProperty(self.request, PROP_KEYS.EVENT_DATE) minimum_age = PROP_KEYS.getProperty(self.request, PROP_KEYS.MINIMUM_AGE) if relativedelta(event_date, dob).years < minimum_age: problem = True self.request.session.flash( "Guests must be aged %i on the day of the event, age entered is too young." % minimum_age, "error") if not problem: ticket.guest_info.dob = dob ticket.guest_info.raven_user = ( "atcambridge" in self.request.POST and self.request.POST["atcambridge"] == "yes") if ticket.guest_info.raven_user: ticket.guest_info.crsid = self.request.POST["crsid"] ticket.guest_info.email = ticket.guest_info.crsid + "@cam.ac.uk" ticket.guest_info.college = self.request.POST["college"] ticket.guest_info.grad_status = self.request.POST[ "grad_status"] return HTTPFound(location=self.request.route_path( "admin_ticket_guest_info", ticket_id=ticket.__name__)) if ticket.guest_info == None: ticket.guest_info = UserProfile() ticket.guest_info.__parent__ = ticket info = ticket.guest_info dob = datetime.now() if info.dob != None: dob = info.dob return { "ticket_id": ticket.__name__, "title": info.title, "othertitle": (info.title not in ["Mr", "Mrs", "Miss", "Ms", "Dr", "Prof", "Rev"] and len(info.title) > 0), "forename": info.forename, "surname": info.surname, "email": info.email, "dob_year": dob.year, "dob_month": dob.month, "dob_day": dob.day, "atcambridge": info.raven_user, "crsid": info.crsid, "college": info.college, "grad_status": info.grad_status }