def set_broadcast_types(service_user, broadcast_types, force=False): for bt in broadcast_types: if not bt: raise InvalidBroadcastTypeException(bt) broadcast_types_set = set() unduplicated_broadcast_types = [bt for bt in broadcast_types if not (bt in broadcast_types_set or broadcast_types_set.add(bt))] def trans(): service_profile = get_service_profile(service_user, False) update_scheduled = False bc_settings_items = get_broadcast_settings_items(service_user, -1) if not unduplicated_broadcast_types: if bc_settings_items: if not force: raise CanNotDeleteBroadcastTypesException() db.delete(bc_settings_items) bump_menuGeneration_of_all_identities_and_update_friends(service_user) update_scheduled = True service_profile.broadcastTypes = unduplicated_broadcast_types service_profile.version += 1 service_profile.put() if not update_scheduled and bc_settings_items: schedule_update_all_friends_of_service_user(service_profile, force) run_in_transaction(trans)
def put_all_static_content(cursor=None): qry = SolutionStaticContent.all() qry.with_cursor(cursor) models = qry.fetch(200) new_models = list() if not models: return for m in models: tmp = m.key().name().split("x", 2) coords = [int(tmp[1]), int(tmp[2]), int(tmp[0])] new_model = SolutionStaticContent(parent=parent_key( m.service_user, SOLUTION_COMMON), coords=coords, old_coords=coords, sc_type=m.sc_type, icon_label=m.icon_label, icon_name=m.icon_name, text_color=m.text_color, background_color=m.background_color, html_content=m.html_content, branding_hash=m.branding_hash, visible=True, provisioned=True, deleted=False) new_models.append(new_model) def trans(): db.put(new_models) db.delete(models) run_in_transaction(trans, True) deferred.defer(put_all_static_content, qry.cursor(), _queue=MIGRATION_QUEUE)
def testTransactionActions(self): def trans(): transActionsCount = TransactionActionsCount(key=TransactionActionsCount.create_key()) transActionsCount.count = 0 transActionsCount.put() on_trans_committed(update_count, False) on_trans_committed(update_count, False) on_trans_committed(update_count, True) on_trans_committed(update_count, False) on_trans_committed(update_count, False) def update_count(should_raise): transActionsCount = TransactionActionsCount.get(TransactionActionsCount.create_key()) transActionsCount.count += 1 if should_raise: raise TransactionFailedError() transActionsCount.put() run_in_transaction(trans) def check_count(): transActionsCount = TransactionActionsCount.get(TransactionActionsCount.create_key()) self.assertEqual(4, transActionsCount.count) run_in_transaction(check_count)
def set_service_disabled(service_user): """ Disconnects all connected users, stores them in an archive and deletes the service from search index. """ from rogerthat.bizz.service import _cleanup_search_index, SERVICE_INDEX, SERVICE_LOCATION_INDEX def trans(): to_put = list() service_profile = get_service_profile(service_user) service_profile.expiredAt = now() service_profile.enabled = False to_put.append(service_profile) service_identity_keys = get_service_identities_query(service_user, True) search_configs = db.get( [SearchConfig.create_key(create_service_identity_user(users.User(key.parent().name()), key.name())) for key in service_identity_keys]) svc_index = search.Index(name=SERVICE_INDEX) loc_index = search.Index(name=SERVICE_LOCATION_INDEX) for search_config in search_configs: if search_config: search_config.enabled = False to_put.append(search_config) on_trans_committed(_cleanup_search_index, search_config.service_identity_user.email(), svc_index, loc_index) for objects_to_put in chunks(to_put, 200): put_and_invalidate_cache(*objects_to_put) deferred.defer(cleanup_sessions, service_user, _transactional=True) deferred.defer(cleanup_friend_connections, service_user, _transactional=True) run_in_transaction(trans, True)
def testTransactionActionsWithNestedTrans(self): raised = [False] # we only want to raise 1 time def trans(): transActionsCount = TransactionActionsCount(key=TransactionActionsCount.create_key()) transActionsCount.count = 0 transActionsCount.put() on_trans_committed(update_count, False) on_trans_committed(update_count, False) on_trans_committed(update_count, True) on_trans_committed(update_count, False) on_trans_committed(update_count, False) def update_count(should_raise): def inner_trans(should_raise): transActionsCount = TransactionActionsCount.get(TransactionActionsCount.create_key()) transActionsCount.count += 1 if not raised[0] and should_raise: raised[0] = True raise TransactionFailedError() transActionsCount.put() return run_in_transaction(inner_trans, False, should_raise) run_in_transaction(trans) def check_count(): transActionsCount = TransactionActionsCount.get(TransactionActionsCount.create_key()) self.assertEqual(5, transActionsCount.count) run_in_transaction(check_count)
def create_service_profile(service_user, name, is_trial=False, update_func=None, supported_app_ids=None): from rogerthat.bizz.service import create_default_qr_templates from rogerthat.bizz.news import create_default_news_settings name = _validate_name(name) if supported_app_ids is None: default_app = app.get_default_app() default_app_id = default_app.app_id if default_app else App.APP_ID_ROGERTHAT supported_app_ids = [default_app_id] else: default_app_id = supported_app_ids[0] def trans_prepare_create(): avatar, image = _create_new_avatar(service_user, is_trial) from rogerthat.bizz.service import _create_recommendation_qr_code share_sid_key = _create_recommendation_qr_code(service_user, ServiceIdentity.DEFAULT, default_app_id) return avatar, image, share_sid_key def trans_create(avatar, image, share_sid_key): azzert(not get_service_profile(service_user, cached=False)) azzert(not get_default_service_identity_not_cached(service_user)) profile = ServiceProfile(parent=parent_key(service_user), key_name=service_user.email()) profile.avatarId = avatar.key().id() _calculateAndSetAvatarHash(profile, image) service_identity_user = create_service_identity_user(service_user, ServiceIdentity.DEFAULT) service_identity = ServiceIdentity(key=ServiceIdentity.keyFromUser(service_identity_user)) service_identity.inheritanceFlags = 0 service_identity.name = name service_identity.description = "%s (%s)" % (name, service_user.email()) service_identity.shareSIDKey = share_sid_key service_identity.shareEnabled = False service_identity.creationTimestamp = now() service_identity.defaultAppId = supported_app_ids[0] service_identity.appIds = supported_app_ids update_result = update_func(profile, service_identity) if update_func else None put_and_invalidate_cache(profile, service_identity, ProfilePointer.create(service_user), ProfileHashIndex.create(service_user)) deferred.defer(create_default_qr_templates, service_user, _transactional=True) deferred.defer(create_default_news_settings, service_user, profile.organizationType, _transactional=True) return profile, service_identity, update_result avatar, image, share_sid_key = run_in_transaction(trans_prepare_create, True) try: profile, service_identity, update_result = run_in_transaction(trans_create, True, avatar, image, share_sid_key) return (profile, service_identity, update_result) if update_func else (profile, service_identity) except: db.delete([avatar, share_sid_key]) raise
def save_cityapp_settings(service_user, gather_events, uitdatabank_secret, uitdatabank_key, uitdatabank_regions): def trans(): cap = get_cityapp_profile(service_user) cap.uitdatabank_secret = uitdatabank_secret cap.uitdatabank_key = uitdatabank_key cap.uitdatabank_regions = uitdatabank_regions cap.gather_events_enabled = gather_events cap.put() run_in_transaction(trans, False)
def save_translations(service_translation_set, multi_translation_dict): def trans(): translation_keys = ServiceTranslation.all(keys_only=True).ancestor(service_translation_set).fetch(None) db.delete(translation_keys) to_put = list() for translation_type, translation_dict in multi_translation_dict.iteritems(): to_put.append(ServiceTranslation.create(service_translation_set, translation_type, translation_dict)) db.put(to_put) run_in_transaction(trans)
def _send_app_broadcast_to_user(user_profile, service_identity_user, message, tag, is_test=False): def trans(): app_user = users.User(user_profile.key().name()) if user_profile.isCreatedForService: logging.debug('%s is created for service(s) %s', app_user, user_profile.owningServiceEmails) return service_user = get_service_user_from_service_identity_user(service_identity_user) fsic_key = FriendServiceIdentityConnection.createKey(app_user, service_identity_user) friend_map_key = get_friends_map_key_by_user(app_user) fsic, friend_map, si, service_profile = \ db.get([fsic_key, friend_map_key, ServiceIdentity.keyFromUser(service_identity_user), get_profile_key(service_user)]) azzert(si and service_profile) if fsic and not fsic.deleted: # they are friends alert_flags = Message.ALERT_FLAG_VIBRATE answers = [] step_id = u'Connected' elif friend_map: # Fake a deleted connection between service and human user to be able to show the service's avatar on the phone fake_friend_connection(friend_map_key, si) alert_flags = Message.ALERT_FLAG_SILENT answers = create_add_to_services_button(service_profile.defaultLanguage) step_id = u'Not connected' else: logging.warn(u'No FSIC nor FriendMap found for %s', app_user) return member = UserMemberTO(app_user, alert_flags) flags = Message.FLAG_ALLOW_DISMISS | Message.FLAG_AUTO_LOCK timeout = 0 parent_key = None sender_answer = None branding = si.descriptionBranding if is_test: step_id = None m = sendMessage(service_identity_user, [member], flags, timeout, parent_key, message, answers, sender_answer, branding, tag, check_friends=False, allow_reserved_tag=True, step_id=step_id) m.invitor = service_identity_user m.invitee = app_user m.origin = ORIGIN_SERVICE_INVITE m.servicetag = APP_BROADCAST_TAG m.put() run_in_transaction(trans, xg=True)
def _run_update_friends_by_profile_info(user, friend_type, changed_properties, worker_queue=HIGH_LOAD_WORKER_QUEUE, clear_broadcast_settings_cache=False): def trans(user): helper = FriendHelper.serialize(user, friend_type) if friend_type == FRIEND_TYPE_SERVICE: user = remove_slash_default(user) else: update_friend_service_identity_connections(UserProfile.createKey(user), changed_properties) run_job(get_friends_friends_maps_keys_query, [user], _update_friend, [helper, clear_broadcast_settings_cache], worker_queue=worker_queue) run_in_transaction(trans, True, user)
def check_i18n_status_of_message_flows(service_user): from rogerthat.bizz.service.mfd import render_xml_for_message_flow_design def trans(): translator = get_translator(service_user) mfds = get_multilanguage_message_flow_designs_by_status(service_user, MessageFlowDesign.STATUS_VALID) for mfd in mfds: render_xml_for_message_flow_design(mfd, translator, dict()) put_and_invalidate_cache(*mfds) run_in_transaction(trans, xg=True) channel.send_message(service_user, u'rogerthat.mfd.changes')
def update_service_avatar(service_user, image): img = images.Image(image) img.im_feeling_lucky() img.execute_transforms() if img.height != img.width: devation = float(img.width) / float(img.height) if devation < 0.95 or devation > 1.05: from rogerthat.bizz.service import AvatarImageNotSquareException logging.debug("Avatar Size: %sx%s" % (img.width, img.height)) raise AvatarImageNotSquareException() img = images.Image(image) img.resize(150, 150) image = img.execute_transforms(images.PNG, 100) if is_trial_service(service_user): image = add_trial_service_overlay(image) def trans(): service_profile = get_service_profile(service_user) avatar = get_avatar_by_id(service_profile.avatarId) if not avatar: avatar = Avatar(user=service_profile.user) update_avatar_profile(service_profile, avatar, image) service_profile.version += 1 service_profile.put() from rogerthat.bizz.job.update_friends import schedule_update_all_friends_of_service_user schedule_update_all_friends_of_service_user(service_profile) return run_in_transaction(trans, xg=True)
def update_user_profile(app_user, name, image, language): def trans(): user_profile = get_user_profile(app_user) changed_properties = [] if user_profile.language != language: user_profile.language = language changed_properties.append(u"language") db.delete_async(get_broadcast_settings_flow_cache_keys_of_user(app_user)) if user_profile.name != name: changed_properties.append(u"name") user_profile.name = name if image: _update_avatar(user_profile, image, False) changed_properties.append(u"avatar") user_profile.version += 1 user_profile.put() update_mobiles(app_user, user_profile) # update myIdentity update_friends(user_profile, changed_properties) # notify my friends return user_profile user_profile = run_in_transaction(trans, xg=True) schedule_re_index(app_user) return user_profile
def create_user_profile(app_user, name, language=None, ysaaa=False, owncloud_password=None, image=None, tos_version=None, consent_push_notifications_shown=False): # type: (users.User, unicode, unicode, bool, unicode, unicode, int, bool) -> UserProfile name = _validate_name(name) def trans_create(avatar_image): azzert(not get_user_profile(app_user, cached=False)) avatar, image = _create_new_avatar(app_user, False, avatar_image) user_profile = UserProfile(parent=parent_key(app_user), key_name=app_user.email()) user_profile.name = name user_profile.language = language user_profile.avatarId = avatar.key().id() user_profile.app_id = get_app_id_from_app_user(app_user) user_profile.owncloud_password = owncloud_password if tos_version: user_profile.tos_version = tos_version if consent_push_notifications_shown: user_profile.consent_push_notifications_shown = True _calculateAndSetAvatarHash(user_profile, image) put_and_invalidate_cache(user_profile, ProfilePointer.create(app_user), ProfileHashIndex.create(app_user)) return user_profile user_profile = run_in_transaction(trans_create, True, image) if not ysaaa: schedule_re_index(app_user) return user_profile
def finish_login_state(state, token): def trans(): login_state = PaymentOauthLoginState.create_key(state).get() if not login_state: return False if login_state.completed: return False login_state.completed = True login_state.put() payment_user_key = get_payment_user_key(login_state.app_user) payment_user = payment_user_key.get() if not payment_user: payment_user = PaymentUser(key=payment_user_key) payment_user.providers = [] payment_user.assets = [] pup = payment_user.get_provider(login_state.provider_id) if pup: pup.token = token else: payment_user.providers.append(PaymentUserProvider(provider_id=login_state.provider_id, token=token)) payment_user.put() deferred.defer(sync_payment_assets, login_state.app_user, login_state.provider_id, True, _transactional=True) return True return run_in_transaction(trans, True)
def set_logo(service_user, image): logging.info('%s: Saving logo' % service_user.email()) _meta, img_b64 = image.split(',') jpg_bytes = base64.b64decode(img_b64) def trans(): logo = get_solution_logo(service_user) or SolutionLogo( key=SolutionLogo.create_key(service_user)) logo.picture = db.Blob(jpg_bytes) logo.is_default = False settings = get_solution_settings(service_user) settings.updates_pending = True put_and_invalidate_cache(logo, settings) deferred.defer(_regenerate_branding_with_logo, service_user, _transactional=True) return settings common_settings = run_in_transaction(trans, xg=True) send_message(common_settings.service_user, 'solutions.common.settings.logo.updated') broadcast_updates_pending(common_settings)
def _regenerate_branding_with_logo(service_user): users.set_user(service_user) logging.info( "%s: Replacing logo.png in the sln main branding zip with the uploaded logo" % service_user.email()) logo = get_solution_logo(service_user) sln_main_branding = get_solution_main_branding(service_user) zip_content = replace_file_in_zip_blob(sln_main_branding.blob, "logo.jpg", str(logo.picture)) def trans(): sln_main_branding = get_solution_main_branding(service_user) sln_main_branding.blob = db.Blob(zip_content) sln_main_branding.branding_creation_time = 0 common_settings = get_solution_settings(service_user) common_settings.updates_pending = True common_settings.events_branding_hash = None put_and_invalidate_cache(sln_main_branding, common_settings) return common_settings common_settings = run_in_transaction(trans, xg=True) broadcast_updates_pending(common_settings)
def export_user_data(app_user, data_export_email): human_user, app_id = get_app_user_tuple(app_user) date = format_datetime(datetime.datetime.now(), locale='en', format='yyyy_MM_dd') result_path = '/%s/users/%s/%s' % (EXPORTS_BUCKET, app_user.email(), date) def update(): user_data_export_key = UserDataExport.create_key(app_user, date) user_data_export = UserDataExport.get(user_data_export_key) if user_data_export: return user_data_export.data_export_email user_data_export = UserDataExport(key=user_data_export_key) user_data_export.creation_time = now() user_data_export.data_export_email = data_export_email user_data_export.put() counter = ExportUserPipeline(result_path, human_user.email(), app_id, data_export_email) task = counter.start(return_task=True) task.add(queue_name=DATA_EXPORT_QUEUE, transactional=True) redirect_url = "%s/status?root=%s" % (counter.base_path, counter.pipeline_id) logging.info("export pipeline url: %s", redirect_url) return None return run_in_transaction(update, xg=True)
def set_avatar(service_user, image): logging.info('%s: Saving avatar' % service_user.email()) _meta, img_b64 = image.split(',') jpg_bytes = base64.b64decode(img_b64) def trans(): avatar_key = SolutionAvatar.create_key(service_user) avatar, branding_settings, sln_settings = db.get( (avatar_key, SolutionBrandingSettings.create_key(service_user), SolutionSettings.create_key(service_user))) avatar = avatar or SolutionAvatar(key=avatar_key) avatar.picture = db.Blob(jpg_bytes) avatar.published = False avatar.is_default = False to_put = [avatar, sln_settings] sln_settings.updates_pending = True if branding_settings: branding_settings.modification_time = now() to_put.append(branding_settings) put_and_invalidate_cache(*to_put) return sln_settings sln_settings = run_in_transaction(trans, xg=True) send_message(sln_settings.service_user, 'solutions.common.settings.avatar.updated') broadcast_updates_pending(sln_settings)
def update_count(should_raise): def inner_trans(should_raise): transActionsCount = TransactionActionsCount.get(TransactionActionsCount.create_key()) transActionsCount.count += 1 if not raised[0] and should_raise: raised[0] = True raise TransactionFailedError() transActionsCount.put() return run_in_transaction(inner_trans, False, should_raise)
def _populate_new_editable_set(service_user): '''copy active content to editable service translation set''' def trans(): puts = list() service_profile = get_service_profile(service_user) editable_translation_set_key = db.Key(encoded=service_profile.editableTranslationSet) active_translation_set_key = db.Key(encoded=service_profile.activeTranslationSet) active_translations = ServiceTranslation.all().ancestor(active_translation_set_key).fetch(None) for active_translation in active_translations: editable_translation = ServiceTranslation.create(editable_translation_set_key, active_translation.translation_type, active_translation.translation_dict) puts.append(editable_translation) db.put(puts) logging.debug("Copying active translation set into the new editable translation set") run_in_transaction(trans, xg=True)
def store_branding_zip(service_user, zip_, description, skip_meta_file=False): # type: (users.User, ZipFile, unicode) -> Branding try: pokes, html, branding_type, meta_properties = _parse_and_validate_branding_zip(zip_) # Remove previously added dimensions: html = re.sub("<meta\\s+property=\\\"rt:dimensions\\\"\\s+content=\\\"\\[\\d+,\\d+,\\d+,\\d+\\]\\\"\\s*/>", "", html) try: zip_content = _create_new_zip(service_user, branding_type, zip_, html, skip_meta_file) except BadZipfile, e: raise BadBrandingZipException(reason=e.message) _validate_branding_size(zip_content, branding_type) hash_ = calculate_branding_hash(branding_type, zip_content) b = Branding.get_by_key_name(hash_) if b and b.user != service_user: raise BrandingAlreadyExistsException() def trans(): return _create_branding(hash_, zip_content, description, service_user, branding_type, meta_properties, pokes) branding = run_in_transaction(trans, True) # # Try to add dimension information # if "</head>" in html: settings = get_server_settings() if not settings.brandingRendererUrl or branding_type in (Branding.TYPE_APP, Branding.TYPE_CORDOVA,): return branding if meta_properties.get('display-type', Branding.DISPLAY_TYPE_WEBVIEW) == Branding.DISPLAY_TYPE_NATIVE: return branding try: url = "%s?%s" % (settings.brandingRendererUrl, urllib.urlencode( (('url', get_server_settings().baseUrl + '/branding/' + hash_ + '/branding.html?xrender=true'),))) response = urlfetch.fetch(url, deadline=10) if response.status_code != 200: logging.error("Could not render branding to get dimensions.\n%s" % response.content) return branding except: logging.warn("Failed to render dimensions") return branding html = html.replace("</head>", '<meta property="rt:dimensions" content="' + response.content + '" /></head>') else: return branding zip_content = _create_new_zip(service_user, branding_type, zip_, html)
def save_broadcast_types_order(service_user, broadcast_types): def trans(): sln_settings = get_solution_settings(service_user) translated_broadcast_types = get_translated_broadcast_types( sln_settings) diff = set(translated_broadcast_types).symmetric_difference( broadcast_types) if diff: raise InvalidBroadcastTypeException(diff.pop()) sln_settings.broadcast_types = [ translated_broadcast_types[bt] for bt in broadcast_types ] sln_settings.updates_pending = True put_and_invalidate_cache(sln_settings) broadcast_updates_pending(sln_settings) run_in_transaction(trans, True)
def put_loyalty_user_profile(email, app_id, user_code, short_url_id, language): app_user = create_app_user(users.User(email), app_id) name = _validate_name(email) def trans_create(): rogerthat_profile = get_service_or_user_profile(users.User(email)) if rogerthat_profile and isinstance(rogerthat_profile, ServiceProfile): from rogerthat.bizz.service import AppFailedToCreateUserProfileWithExistingServiceException raise AppFailedToCreateUserProfileWithExistingServiceException(email) user_profile = get_user_profile(app_user, cached=False) is_new_profile = False if not user_profile: deactivated_user_profile = get_deactivated_user_profile(app_user) if deactivated_user_profile: deferred.defer(reactivate_user_profile, deactivated_user_profile, app_user, _transactional=True) ActivationLog(timestamp=now(), email=app_user.email(), mobile=None, description="Reactivate user account by registering a paper loyalty card").put() else: is_new_profile = True avatar, image = _create_new_avatar(app_user, add_trial_overlay=False) user_profile = UserProfile(parent=parent_key(app_user), key_name=app_user.email()) user_profile.name = name user_profile.language = language user_profile.avatarId = avatar.key().id() user_profile.app_id = app_id _calculateAndSetAvatarHash(user_profile, image) pp = ProfilePointer(key=db.Key.from_path(ProfilePointer.kind(), user_code)) pp.user = app_user pp.short_url_id = short_url_id if is_new_profile: put_and_invalidate_cache(user_profile, pp, ProfilePointer.create(app_user)) else: pp.put() run_in_transaction(trans_create, True) schedule_re_index(app_user) return app_user
def update_translation_of_type(service_user, translation_type, translation_strings): """Update service translation of translation_type with new keys Args: service_user (users.User) translation_type (int): e.g. ServiceTranslation.MFLOW_TEXT translation_strings (dict): """ def trans(): editable_translation_set = get_editable_translation_set(service_user) should_create = not editable_translation_set if should_create: editable_translation_set = ServiceTranslationSet.create_editable_set(service_user) editable_translation_set.put() return should_create, editable_translation_set @run_after_transaction def update_service_profile(translation_set): def inner_trans(): service_profile = get_service_profile(service_user) service_profile.editableTranslationSet = str(translation_set.key()) service_profile.put() run_in_transaction(inner_trans) is_new_set, editable_translation_set = run_in_transaction(trans, xg=True) if is_new_set: update_service_profile(editable_translation_set) all_translations = get_all_translations(editable_translation_set) type_name = ServiceTranslation.TYPE_MAP[translation_type] logging.info('Merging %s translations into the service translations', type_name) logging.debug('New %s translation keys: %s', type_name, translation_strings) logging.debug('Existing translations: %s', all_translations) translations_dict = all_translations.setdefault(translation_type, dict()) updated = False for default_string in translation_strings: if default_string not in translations_dict: translations_dict[default_string] = None updated = True if updated: logging.debug('Updated translations: %s', all_translations) save_translations(editable_translation_set, all_translations) # convert "pt-br" keys to "pt_BR" before returning for translations in translations_dict.itervalues(): if translations: for lang in translations.keys(): translations[get_iso_lang(lang)] = translations.pop(lang) return translations_dict, updated
def update_service_profile(service_user, image, add_trial_overlay): from rogerthat.bizz.job.update_friends import schedule_update_all_friends_of_service_user def trans(): service_profile = get_service_profile(service_user) if image: _update_avatar(service_profile, image, add_trial_overlay) service_profile.version += 1 service_profile.put() schedule_update_all_friends_of_service_user(service_profile) return run_in_transaction(trans, True)
def deploy_translation(service_user): def trans(): to_put = set() service_profile = get_service_profile(service_user) if not service_profile.editableTranslationSet: logging.error("Deploy translation error - no editable translation found for svc %s" % service_user.email()) return # 1. Archive old active translation set if service_profile.activeTranslationSet: old_active_translation_set = ServiceTranslationSet.get(service_profile.activeTranslationSet) old_active_translation_set.status = ServiceTranslationSet.ARCHIVED to_put.add(old_active_translation_set) # 2. Promote old editable translation set to new active service_profile.activeTranslationSet = service_profile.editableTranslationSet to_put.add(service_profile) new_active_translation_set = ServiceTranslationSet.get(service_profile.activeTranslationSet) new_active_translation_set.status = ServiceTranslationSet.ACTIVE to_put.add(new_active_translation_set) # 3. Create new editable translation set new_editable_translation_set = ServiceTranslationSet.create_editable_set(service_user) new_editable_translation_set.latest_export_timestamp = new_active_translation_set.latest_export_timestamp service_profile.editableTranslationSet = str(new_editable_translation_set.key()) to_put.add(new_editable_translation_set) # 4. Copy existing translations to new branding_translations_dict = None for tr in ServiceTranslation.all().ancestor(new_active_translation_set).fetch(None): translation_dict = tr.translation_dict if tr.translation_type == ServiceTranslation.BRANDING_CONTENT: branding_translations_dict = translation_dict to_put.add(ServiceTranslation.create(new_editable_translation_set, tr.translation_type, translation_dict)) # 5. Store all in db put_and_invalidate_cache(*to_put) return service_profile, branding_translations_dict service_profile, branding_translations_dict = run_in_transaction(trans, xg=True) if len(service_profile.supportedLanguages) > 1: if branding_translations_dict: deferred.defer(_translate_all_app_brandings, service_user, Branding.TYPE_APP, branding_translations_dict) deferred.defer(_translate_all_app_brandings, service_user, Branding.TYPE_CORDOVA, branding_translations_dict) deferred.defer(_translate_all_message_flows, service_user) deferred.defer(_update_i18n_search_configs, service_user) deferred.defer(_populate_new_editable_set, service_user)
def test_change_order_to_free(self): self.set_datastore_hr_probability(1) products_to_order = [(u'MSUP', 12), # monthly subscription, $50.00 (u'KSUP', 12), # subscription discount, -$15.00 (Product.PRODUCT_EXTRA_CITY, 12), # extra city, $5.00 (Product.PRODUCT_EXTRA_CITY, 12), # extra city, $5.00 (Product.PRODUCT_EXTRA_CITY, 12)] # extra city, $5.00 old_subscription_order, customer = self._create_customer_and_subscription_order(products_to_order) old_subscription_order.next_charge_date -= 12 * 31 * 86400 # Turn back next_charge_date more than 12 months old_subscription_order.put() self._create_service(customer, [u'be-loc', u'be-berlare', u'be-beveren', u'es-madrid', App.APP_ID_ROGERTHAT, App.APP_ID_OSA_LOYALTY]) # Creating some random order with a discount to be sure this discount isn't applied in recurrent billing job self._create_order(customer, old_subscription_order.contact_id, self._create_items(customer, [(u'KLUP', 1), (u'LSUP', 1)])) products_to_order = [(Product.PRODUCT_FREE_SUBSCRIPTION, 1), (Product.PRODUCT_EXTRA_CITY, 1), # extra city, $5.00 (Product.PRODUCT_EXTRA_CITY, 1), # extra city, $5.00 (Product.PRODUCT_EXTRA_CITY, 1)] # extra city, $5.00 order_items = self._create_items(customer, products_to_order) new_subscription_order, customer = self._create_order(customer, old_subscription_order.contact_id, order_items, replace=True) new_subscription_order.next_charge_date -= 12 * 31 * 86400 # Turn back next_charge_date more than 12 months new_subscription_order.put() # Execute recurrent billing code products = Product.get_products_dict() charge = _create_charge(new_subscription_order.key(), now(), products) self.assertIsNotNone(charge) expected_charge_amount = 3 * products[Product.PRODUCT_EXTRA_CITY].price # 3x $5.00 self.assertEqual(expected_charge_amount, charge.amount) def trans_invoice_number(): return InvoiceNumber.next(get_mobicage_legal_entity()) invoice_number = run_in_transaction(trans_invoice_number) create_invoice(customer.id, new_subscription_order.order_number, charge.id, invoice_number, new_subscription_order.manager, payment_type=Invoice.PAYMENT_ON_SITE) dt = datetime.datetime.utcnow() invoices = export_invoices(dt.year, dt.month) self.assertEqual(1, len(invoices)) self.assertEqual(len(products_to_order), len(invoices[0]['order_items'])) order_items_cost = sum(order_item['price'] * order_item['count'] for order_item in invoices[0]['order_items']) self.assertEqual(expected_charge_amount, order_items_cost)
def hookup(app_user, acs, service_helper): # type: (users.User, AutoConnectedService, FriendCloudStorageHelper) -> None def trans(): user_profile = get_user_profile(app_user) if user_profile.isCreatedForService: return ui = get_user_interaction(app_user) if acs.service_identity_email not in ui.services: service_identity_user = users.User(acs.service_identity_email) do_make_friends = True if acs.service_roles: do_make_friends = False # is app_user in one of the roles? service_user, si_id = get_service_identity_tuple(service_identity_user) synced_roles = list() for service_role in get_service_roles_by_ids(service_user, acs.service_roles): if user_profile.has_role(service_identity_user, u'%s' % service_role.role_id): do_make_friends = True break elif service_role.type == ServiceRole.TYPE_SYNCED: synced_roles.append(service_role) else: # for loop did not reach BREAK: user_profile does not have any role --> send friend.is_in_roles user_details = [UserDetailsTO.fromUserProfile(user_profile)] send_is_in_roles(app_user, get_service_profile(service_user), si_id, user_details, map(RoleTO.fromServiceRole, synced_roles), make_friends_if_in_role=True) if do_make_friends: ui.services.append(acs.service_identity_email) ui.put() logging.info("Connecting %s with auto-connected service %s", app_user, acs.service_identity_email) deferred.defer(makeFriends, service_identity_user, app_user, app_user, None, notify_invitee=False, origin=ORIGIN_USER_INVITE, service_helper=service_helper, _transactional=True, _queue=HIGH_LOAD_WORKER_QUEUE) run_in_transaction(trans, True)
def _delete_static_content(service_user, static_content_id): sln_settings, sc = db.get( (SolutionSettings.create_key(service_user), SolutionStaticContent.create_key(service_user, static_content_id))) def trans(): sc.provisioned = False sc.deleted = True sln_settings.updates_pending = True db.put([sln_settings, sc]) return sln_settings sln_settings = run_in_transaction(trans, True) send_message(service_user, u"solutions.common.service_menu.updated") broadcast_updates_pending(sln_settings)
def store_branding_zip(service_user, zip_, description): try: pokes, html, contains_app_html, meta_properties = _parse_and_validate_branding_zip(zip_) # Remove previously added dimensions: html = re.sub("<meta\\s+property=\\\"rt:dimensions\\\"\\s+content=\\\"\\[\\d+,\\d+,\\d+,\\d+\\]\\\"\\s*/>", "", html) try: zip_content, type_ = _create_new_zip(service_user, zip_, html) except BadZipfile, e: raise BadBrandingZipException(reason=e.message) _validate_branding_size(zip_content, type_) hash_ = hashlib.sha256(zip_content).hexdigest().upper() b = Branding.get_by_key_name(hash_) if b and b.user != service_user: raise BrandingAlreadyExistsException() def trans(): return _create_branding(hash_, zip_content, description, service_user, contains_app_html, meta_properties, pokes) branding = run_in_transaction(trans, True) # # Try to add dimension information # if "</head>" in html: settings = get_server_settings() if not settings.brandingRendererUrl or not type_ == TYPE_BRANDING: return branding try: url = "%s?%s" % (settings.brandingRendererUrl, urllib.urlencode((('url', get_server_settings().baseUrl + '/branding/' + hash_ + '/branding.html?xrender=true'),))) response = urlfetch.fetch(url, deadline=10) if response.status_code != 200: logging.error("Could not render branding to get dimensions.\n%s" % response.content) return branding except: logging.exception("Failed to render dimensions") return branding html = html.replace("</head>", '<meta property="rt:dimensions" content="' + response.content + '" /></head>') else: return branding zip_content, _ = _create_new_zip(service_user, zip_, html)
def revoke_role(service_identity_user, user, role): admin = False service_identity = get_service_identity(service_identity_user) if not service_identity: raise ServiceIdentityDoesNotExistException(get_identity_from_service_identity_user(service_identity_user)) if isinstance(role, unicode): admin = True azzert(role in ROLES) # builtin role_str = role else: azzert(role.service_user == service_identity.service_user) role_str = u'%s' % role.role_id def trans(): new_look_and_feel = None new_look_and_feel_id = None look_n_feel_changed = False user_profile = get_user_profile(user, False) user_profile.revoke_role(service_identity_user, role_str) if not admin and user_profile.look_and_feel_id: look_and_feel = AppLookAndFeel.get_by_id(user_profile.look_and_feel_id) for role_mapping in look_and_feel.roles: # type: LookAndFeelServiceRoles if role.role_id in role_mapping.role_ids: new_look_and_feel = get_look_and_feel_for_user(user_profile, ignore_role=role.role_id) if new_look_and_feel: new_look_and_feel_id = new_look_and_feel.key.id() break if user_profile.look_and_feel_id: if not new_look_and_feel_id or user_profile.look_and_feel_id != new_look_and_feel_id: look_n_feel_changed = True user_profile.look_and_feel_id = new_look_and_feel_id user_profile.put() return new_look_and_feel, look_n_feel_changed new_look_n_feel, look_n_feel_changed = run_in_transaction(trans) if admin: deferred.defer(drop_sessions_of_user, user) _send_admin_role_updates(service_identity_user) if look_n_feel_changed: send_look_and_feel_update(user, new_look_n_feel)
def serialize(cls, user, friend_type): # type: (users.User, int) -> FriendCloudStorageHelper if friend_type == FriendTO.TYPE_SERVICE: assert '/' in user.email() datastore_helper = FriendHelper.from_data_store(user, friend_type) def trans(): data = {} flow_keys = [] for method in ('get_service_profile', 'get_profile_info', 'list_service_menu_items', 'list_roles', 'get_share_sid', '_get_all_translations', 'get_service_data', 'get_brandings'): logging.debug('Serializing result of %s', method) f = getattr(datastore_helper, method) obj = f() if obj: if isinstance(obj, dict) or not isinstance(obj, collections.Iterable): data[method] = obj else: is_menu_items_method = method == 'list_service_menu_items' for i, model in enumerate(obj): data['%s-%s' % (method, i)] = model if is_menu_items_method and model.staticFlowKey: flow_keys.append(model.staticFlowKey) if flow_keys: flows = db.get(flow_keys) for flow in flows: data['flow-%s' % flow.key()] = flow return data # TODO: Change xg to False once ServiceTranslationSet uses same parent key as other service data data = run_in_transaction(trans, xg=True) with closing(StringIO.StringIO()) as stream: s_any(stream, data) serialized_value = stream.getvalue() serialized_length = len(serialized_value) logging.info('Size of serialized FriendHelper for %s: %d', user, serialized_length) cloud_storage_path = FriendCloudStorageHelper.create_cloudstorage_path(user.email()) with cloudstorage.open(cloud_storage_path, 'w') as f: f.write(serialized_value) datastore_helper.add_to_memcache(cloud_storage_path, serialized_value) return FriendCloudStorageHelper.from_cloud_storage(user, friend_type, cloud_storage_path)
def update_service_profile(service_user, tmp_avatar_key, x1, y1, x2, y2, add_trial_overlay, organization_type=None): if not tmp_avatar_key and organization_type is None: logging.info("No tmp_avatar_key. Service user pressed save without changing his avatar.") return get_service_profile(service_user) def trans(): service_profile = get_service_profile(service_user) if tmp_avatar_key: _update_avatar(service_profile, tmp_avatar_key, x1, y1, x2, y2, add_trial_overlay) if organization_type is not None: service_profile.organizationType = organization_type service_profile.version += 1 service_profile.put() from rogerthat.bizz.job.update_friends import schedule_update_all_friends_of_service_user schedule_update_all_friends_of_service_user(service_profile) return service_profile return run_in_transaction(trans, True)
def update_user_profile(app_user, name, tmp_avatar_key, x1, y1, x2, y2, language): def trans(): user_profile = get_user_profile(app_user) if user_profile.language != language: user_profile.language = language db.delete_async(get_broadcast_settings_flow_cache_keys_of_user(app_user)) user_profile.name = name if tmp_avatar_key: _update_avatar(user_profile, tmp_avatar_key, x1, y1, x2, y2, add_trial_overlay=False) user_profile.version += 1 user_profile.put() update_mobiles(app_user, user_profile) # update myIdentity update_friends(user_profile) # notify my friends return user_profile user_profile = run_in_transaction(trans, xg=True) schedule_re_index(app_user) return user_profile
def remove_regio_manager(manager_email): logging.info('Removing regional manager %s', manager_email) bizz_check( manager_email != STORE_MANAGER, 'Deleting the <Customer shop> regional manager is not allowed.') task_list = ShopTask.group_by_assignees([manager_email]) task_count = len(task_list[manager_email]) bizz_check( task_count == 0, 'There are still %s tasks assigned to this regional manager' % task_count) def trans(): manager_key = RegioManager.create_key(manager_email) manager = RegioManager.get(manager_key) if not manager.team_id: raise BusinessException( 'Cannot delete regional manager that has no team.') team = manager.team if not team.support_manager: raise BusinessException( 'Cannot delete regional manager: Team \'%s\' has no support manager' % team.name) if team.support_manager == manager_email: raise BusinessException( 'You cannot delete the support manager of a team.' ' Assign this role to a different regional manager first.') team.regio_managers.remove(manager_email) db.delete( [manager_key, RegioManagerStatistic.create_key(manager_email)]) team.put() return team team = run_in_transaction(trans, xg=True) deferred.defer(_unassign_prospects, manager_email) deferred.defer(_change_charges_manager, manager_email, team.support_manager) deferred.defer(_change_orders_manager, manager_email, team.support_manager) deferred.defer(_change_customers_manager, manager_email)
def create_user_profile(app_user, name, language=None, ysaaa=False): name = _validate_name(name) def trans_create(): azzert(not get_user_profile(app_user, cached=False)) avatar, image = _create_new_avatar(app_user, add_trial_overlay=False) user_profile = UserProfile(parent=parent_key(app_user), key_name=app_user.email()) user_profile.name = name user_profile.language = language user_profile.avatarId = avatar.key().id() user_profile.app_id = get_app_id_from_app_user(app_user) _calculateAndSetAvatarHash(user_profile, image) put_and_invalidate_cache(user_profile, ProfilePointer.create(app_user), ProfileHashIndex.create(app_user)) return user_profile user_profile = run_in_transaction(trans_create, True) if not ysaaa: schedule_re_index(app_user) return user_profile
def store_app_qr_template(app_id, data): """ Args: app_id (unicode) data (rogerthat.to.app.CreateAppQRTemplateTO) """ from rogerthat.bizz.app import get_app def trans(): app = get_app(app_id) picture = base64.b64decode(data.file) key_name = QRTemplate.create_key_name(app_id, data.description) template = store_template(None, picture, data.description, data.body_color, key_name) if data.is_default: app.qrtemplate_keys.insert(0, key_name) else: app.qrtemplate_keys.append(template.key().name()) app.put() return template template = run_in_transaction(trans, xg=True) return template, data.is_default
def grant_roles(service_identity_user, user, roles): service_identity = get_service_identity(service_identity_user) if not service_identity: raise ServiceIdentityDoesNotExistException(get_identity_from_service_identity_user(service_identity_user)) admin = False role_ids = [] for role in roles: if isinstance(role, unicode): admin = True azzert(role in ROLES) # builtin role_ids.append(role) else: azzert(role.service_user == service_identity.service_user) role_ids.append(u'%s' % role.role_id) def trans(): look_and_feel = None user_profile = get_user_profile(user, False) bizz_check(user_profile, 'User %s does not exist' % user.email()) for role_id in role_ids: user_profile.grant_role(service_identity_user, role_id) if not user_profile.look_and_feel_id: look_n_feel = get_look_and_feel_for_user(user_profile) if look_n_feel: user_profile.look_and_feel_id = look_n_feel.id look_and_feel = look_n_feel user_profile.put() return look_and_feel look_n_feel = run_in_transaction(trans) if admin: _send_admin_role_updates(service_identity_user) if look_n_feel: send_look_and_feel_update(user, look_n_feel)
def _order_received(service_user, message_flow_run_id, member, steps, end_id, end_message_flow_id, parent_message_key, tag, result_key, flush_id, flush_message_flow_id, service_identity, user_details): from solutions.common.bizz.messaging import send_inbox_forwarders_message for step in steps: if step.step_id == u'message_advanced_order': order_type = ORDER_TYPE_ADVANCED break else: order_type = ORDER_TYPE_SIMPLE def get_extended_details_from_tag(details): if tag and tag.startswith('{') and tag.endswith('}'): try: new_details = u"" tag_dict = json.loads(tag) for k, v in tag_dict.iteritems(): if not k.startswith("_"): if new_details: new_details = u"%s\n%s: %s" % (new_details, k, v) else: new_details = u"%s: %s" % (k, v) if new_details: return u"%s\n%s" % (new_details, details) except: pass return details def trans(): sln_settings = get_solution_settings(service_user) order_settings = get_solution_order_settings(sln_settings) lang = sln_settings.main_language comment = None phone = None takeaway_time = None if order_type == ORDER_TYPE_SIMPLE: details = get_extended_details_from_tag( _get_value(steps[0], u'message_details')) if steps[1].answer_id == u"positive": picture_url = _get_value(steps[1], u'message_picture') att = AttachmentTO() att.content_type = AttachmentTO.CONTENT_TYPE_IMG_JPG att.download_url = picture_url att.name = translate(lang, SOLUTION_COMMON, u'picture') att.size = 0 attachments = [att] else: picture_url = None attachments = [] phone = _get_value(steps[2], u'message_phone') msg = common_translate(lang, SOLUTION_COMMON, 'if-order-received') % { 'remarks': details, 'phone_number': phone } elif order_type == ORDER_TYPE_ADVANCED: with closing(StringIO()) as order: timezone_offset = datetime.datetime.now( pytz.timezone( sln_settings.timezone)).utcoffset().total_seconds() has_order_items = False for step in steps: if step.step_id == u'message_phone': phone = step.get_value() elif step.step_id == u'message_comment': comment = step.get_value() elif step.step_id == u'message_advanced_order': step_value = step.display_value.encode('utf-8') if step_value: has_order_items = True order.write(step_value) elif step.step_id == u'message_takeaway_time': takeaway_time = int(step.get_value() - timezone_offset) picture_url = None attachments = [] if comment: if has_order_items: order.write('\n\n') c = '%s: %s' % (common_translate( lang, SOLUTION_COMMON, 'reservation-comment'), comment) order.write( c.encode('utf-8') if isinstance(c, unicode) else c) details = get_extended_details_from_tag( order.getvalue().decode('utf-8')) takeaway_datetime = datetime.datetime.fromtimestamp( takeaway_time, tz=get_timezone(sln_settings.timezone)) takeaway_time_str = format_datetime(takeaway_datetime, locale=lang, format='d/M/yyyy H:mm') msg = '%s:\n%s\n%s: %s\n%s: %s' % ( common_translate(lang, SOLUTION_COMMON, 'order_received'), details, common_translate(lang, SOLUTION_COMMON, 'phone_number'), phone, common_translate(lang, SOLUTION_COMMON, 'takeaway_time'), takeaway_time_str) else: raise BusinessException('Unsupported order type %s', order_type) if not order_settings.manual_confirmation: # Waiting for follow-up message deferred.defer(_send_order_confirmation, service_user, lang, message_flow_run_id, member, steps, end_id, end_message_flow_id, parent_message_key, tag, result_key, flush_id, flush_message_flow_id, service_identity, user_details, details, _transactional=db.is_in_transaction()) service_identity_user = create_service_identity_user_wo_default( service_user, service_identity) o = SolutionOrder( parent=parent_key_unsafe(service_identity_user, SOLUTION_COMMON)) o.description = details o.phone_number = phone o.sender = SolutionUser.fromTO(user_details[0]) o.timestamp = now() o.status = SolutionOrder.STATUS_RECEIVED o.picture_url = picture_url o.takeaway_time = takeaway_time o.user = user_details[0].toAppUser() if user_details else None message = create_solution_inbox_message( service_user, service_identity, SolutionInboxMessage.CATEGORY_ORDER, None, False, user_details, steps[2].received_timestamp, msg, True, [picture_url] if picture_url else []) o.solution_inbox_message_key = message.solution_inbox_message_key o.put() message.category_key = unicode(o.key()) message.put() sln_i_settings = get_solution_settings_or_identity_settings( sln_settings, service_identity) sm_data = [{ u"type": u"solutions.common.orders.update" }, { u"type": u"solutions.common.messaging.update", u"message": serialize_complex_value( SolutionInboxMessageTO.fromModel(message, sln_settings, sln_i_settings, True), SolutionInboxMessageTO, False) }] send_message(service_user, sm_data, service_identity=service_identity) app_user = user_details[0].toAppUser() send_inbox_forwarders_message( service_user, service_identity, app_user, msg, dict(if_name=user_details[0].name, if_email=user_details[0].email), message_key=message.solution_inbox_message_key, attachments=attachments, reply_enabled=message.reply_enabled) run_in_transaction(trans, xg=True)
def put_static_content(service_user, static_content): try: if static_content.sc_type == SolutionStaticContent.TYPE_OWN: branding_hash = store_static_content_branding( service_user, static_content.background_color, static_content.text_color, static_content.html_content, static_content.icon_label) elif static_content.sc_type != SolutionStaticContent.TYPE_WEBSITE: raise BusinessException('Invalid static content type') else: branding_hash = None except BrandingValidationException: raise except ServiceApiException: logging.exception('Failed to store static content branding', exc_info=True) raise BusinessException( translate( get_solution_settings(service_user).main_language, SOLUTION_COMMON, 'error-occured-unknown-try-again')) def trans(): sln_settings = get_solution_settings(service_user) new_coords = map(int, [ static_content.position.x, static_content.position.y, static_content.position.z ]) if static_content.id is MISSING or static_content.id is None: sc = SolutionStaticContent(parent=parent_key( service_user, SOLUTION_COMMON), deleted=False) sc.old_coords = new_coords else: sc = SolutionStaticContent.get( SolutionStaticContent.create_key(service_user, static_content.id)) if sc.old_coords != new_coords and sc.provisioned: sc.old_coords = sc.coords sc.icon_label = static_content.icon_label sc.icon_name = static_content.icon_name if static_content.sc_type == SolutionStaticContent.TYPE_OWN: sc.text_color = static_content.text_color sc.background_color = static_content.background_color sc.html_content = static_content.html_content sc.branding_hash = branding_hash elif static_content.sc_type == SolutionStaticContent.TYPE_WEBSITE: sc.website = static_content.website sc.sc_type = static_content.sc_type sc.visible = static_content.visible sc.provisioned = False sc.coords = new_coords sc.put() sln_settings.updates_pending = True put_and_invalidate_cache(sc, sln_settings) return sln_settings sln_settings = run_in_transaction(trans, True) send_message(service_user, u"solutions.common.service_menu.updated") broadcast_updates_pending(sln_settings)