def inject_version(): return {"gamification_engine_version": pkg_resources.get_distribution("gamification-engine").version, "settings_enable_authentication": asbool(get_settings().get("enable_user_authentication", False)), "urlprefix": get_settings().get("urlprefix", "/"), "jsmain": get_jsmain(), "cssmain": get_cssmain() }
def get_dev_apns(): """ http://stackoverflow.com/questions/1762555/creating-pem-file-for-apns Step 1: Create Certificate .pem from Certificate .p12 Command: openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12 Step 2: Create Key .pem from Key .p12 Command : openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12 Step 3: If you want to remove pass phrase asked in second step Command : openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem """ if not hasattr(threadlocal, "dev_apns"): settings = get_settings() cert_file = os.environ.get("APNS_CERT", settings.get("apns.dev.certificate")) key_file = os.environ.get("APNS_KEY", settings.get("apns.dev.key")) sandbox = True # other_helpers.boolify(os.environ.get("APNS_SANDBOX",settings.get("apns.sandbox"))) threadlocal.dev_apns = APNs(use_sandbox=sandbox, cert_file=cert_file, key_file=key_file, enhanced=True) def response_listener(error_response): log.debug("client get error-response: " + str(error_response)) threadlocal.dev_apns.gateway_server.register_response_listener( response_listener) return threadlocal.dev_apns
def get_gcm(): if not hasattr(threadlocal, "gcm"): settings = get_settings() # JSON request API_KEY = os.environ.get("GCM_API_KEY", settings.get("gcm.api_key")) threadlocal.gcm = GCM(API_KEY) return threadlocal.gcm
def increase_multi_values(request): try: doc = request.json_body except: raise APIError(400, "invalid_json", "no valid json body") ret = {} for user_id, values in doc.items(): user = User.get_user(user_id) if not user: raise APIError(404, "user_not_found", "user %s not found" % (user_id, )) for variable_name, values_and_keys in values.items(): for value_and_key in values_and_keys: variable = Variable.get_variable_by_name(variable_name) if asbool(get_settings().get("enable_user_authentication", False)): if not Variable.may_increase(variable, request, user_id): raise APIError( 403, "forbidden", "You may not increase the variable %s for user %s." % (variable_name, user_id)) if not variable: raise APIError(404, "variable_not_found", "variable %s not found" % (variable_name, )) if not 'value' in value_and_key: raise APIError(400, "variable_not_found", "illegal value for %s" % (variable_name, )) value = value_and_key['value'] key = value_and_key.get('key', '') Value.increase_value(variable_name, user, value, key) output = _get_progress(achievements_for_user=user, requesting_user=request.user) output = copy.deepcopy(output) to_delete = list() for i in range(len(output["achievements"])): if len(output["achievements"][i]["new_levels"]) > 0: if "levels" in output["achievements"][i]: del output["achievements"][i]["levels"] if "priority" in output["achievements"][i]: del output["achievements"][i]["priority"] if "goals" in output["achievements"][i]: del output["achievements"][i]["goals"] else: to_delete.append(i) for i in sorted(to_delete, reverse=True): del output["achievements"][i] if len(output["achievements"]) > 0: ret[user_id] = output return ret
def may_view(achievement, requesting_user): if not asbool(get_settings().get("enable_user_authentication", False)): return True if achievement["view_permission"] == "everyone": return True if achievement["view_permission"] == "own" and achievements_for_user[ "id"] == requesting_user["id"]: return True return False
def start_response_with_headers(status, headers, exc_info=None): cookie = SimpleCookie() cookie['X-Auth-Token'] = token_s cookie['X-Auth-Token']['path'] = get_settings().get( "urlprefix", "").rstrip("/") + "/" headers.append( ('Set-Cookie', cookie['X-Auth-Token'].OutputString()), ) return start_response(status, headers, exc_info)
def increase_value(request): """increase a value for the user""" user_id = int(request.matchdict["user_id"]) try: value = float(request.POST["value"]) except: try: doc = request.json_body value = doc["value"] except: raise APIError(400, "invalid_value", "Invalid value provided") key = request.matchdict["key"] if ( "key" in request.matchdict and request.matchdict["key"] is not None) else "" variable_name = request.matchdict["variable_name"] user = User.get_user(user_id) if not user: raise APIError(404, "user_not_found", "user not found") variable = Variable.get_variable_by_name(variable_name) if not variable: raise APIError(404, "variable_not_found", "variable not found") if asbool(get_settings().get("enable_user_authentication", False)): if not Variable.may_increase(variable, request, user_id): raise APIError(403, "forbidden", "You may not increase the variable for this user.") Value.increase_value(variable_name, user, value, key) output = _get_progress(achievements_for_user=user, requesting_user=request.user) output = copy.deepcopy(output) to_delete = list() for i in range(len(output["achievements"])): if len(output["achievements"][i]["new_levels"]) > 0: if "levels" in output["achievements"][i]: del output["achievements"][i]["levels"] if "priority" in output["achievements"][i]: del output["achievements"][i]["priority"] if "goals" in output["achievements"][i]: del output["achievements"][i]["goals"] else: to_delete.append(i) for i in sorted(to_delete, reverse=True): del output["achievements"][i] return output
def delete_user(request): """delete a user completely""" user_id = int(request.matchdict["user_id"]) if asbool(get_settings().get("enable_user_authentication", False)): # ensure that the user exists and we have the permission to update it may_delete = request.has_perm( perm_global_delete_user) or request.has_perm( perm_own_delete_user) and request.user.id == user_id if not may_delete: raise APIError(403, "forbidden", "You may not delete this user.") User.delete_user(user_id) return {"status": "OK"}
def get_cssmain(): debug = asbool(get_settings().get("load_from_webpack_dev_server", False)) if debug: return "http://localhost:3000/static/css/bundle.css" else: modpath = os.path.dirname(sys.modules[__name__].__file__) buildpath = os.path.join(modpath, "build") with open(os.path.join(buildpath, "asset-manifest.json"), "r") as f: manifest = json.load(f) return "/admin/jsstatic/" + lstrip_word(manifest["main.css"], "static/") return None
def delete_subject(request): """delete a subject completely""" subject_id = int(request.matchdict["subject_id"]) if asbool(get_settings().get("enable_user_authentication", False)): # ensure that the subject exists and we have the permission to update it may_delete = request.has_perm( perm_global_delete_subject) or request.has_perm( perm_own_delete_subject) and request.subject.id == subject_id if not may_delete: raise APIError(403, "forbidden", "You may not delete this subject.") Subject.delete_subject(subject_id) return {"status": "OK"}
def register_device(request): try: doc = request.json_body except: raise APIError(400, "invalid_json", "no valid json body") subject_id = int(request.matchdict["subject_id"]) device_id = doc.get("device_id") push_id = doc.get("push_id") device_os = doc.get("device_os") app_version = doc.get("app_version") if not device_id \ or not push_id \ or not subject_id \ or not device_os \ or not app_version: raise APIError( 400, "register_device.required_fields", "Required fields: device_id, push_id, device_os, app_version") if asbool(get_settings().get("enable_user_authentication", False)): may_register = request.has_perm( perm_global_register_device ) or request.has_perm(perm_own_register_device) and str( request.subject.id) == str(subject_id) if not may_register: raise APIError(403, "forbidden", "You may not register devices for this subject.") if not exists_by_expr(t_subjects, t_subjects.c.id == subject_id): raise APIError(404, "register_device.subject_not_found", "There is no subject with this id.") SubjectDevice.add_or_update_device(subject_id=subject_id, device_id=device_id, push_id=push_id, device_os=device_os, app_version=app_version) return {"status": "ok"}
def set_messages_read(request): try: doc = request.json_body except: raise APIError(400, "invalid_json", "no valid json body") subject_id = int(request.matchdict["subject_id"]) if asbool(get_settings().get("enable_user_authentication", False)): may_read_messages = request.has_perm( perm_global_read_messages ) or request.has_perm(perm_own_read_messages) and str( request.subject.id) == str(subject_id) if not may_read_messages: raise APIError(403, "forbidden", "You may not read the messages of this subject.") if not exists_by_expr(t_subjects, t_subjects.c.id == subject_id): raise APIError(404, "set_messages_read.subject_not_found", "There is no subject with this id.") message_id = doc.get("message_id") q = select([t_subject_messages.c.id, t_subject_messages.c.created_at], from_obj=t_subject_messages).where( and_(t_subject_messages.c.id == message_id, t_subject_messages.c.subject_id == subject_id)) msg = DBSession.execute(q).fetchone() if not msg: raise APIError(404, "set_messages_read.message_not_found", "There is no message with this id.") uS = update_connection() uS.execute(t_subject_messages.update().values({ "is_read": True }).where( and_(t_subject_messages.c.subject_id == subject_id, t_subject_messages.c.created_at <= msg["created_at"]))) return {"status": "ok"}
def get_messages(request): try: subject_id = int(request.matchdict["subject_id"]) except: subject_id = None try: offset = int(request.GET.get("offset", 0)) except: offset = 0 limit = 100 if asbool(get_settings().get("enable_user_authentication", False)): may_read_messages = request.has_perm( perm_global_read_messages ) or request.has_perm(perm_own_read_messages) and str( request.subject.id) == str(subject_id) if not may_read_messages: raise APIError(403, "forbidden", "You may not read the messages of this subject.") if not exists_by_expr(t_subjects, t_subjects.c.id == subject_id): raise APIError(404, "get_messages.subject_not_found", "There is no subject with this id.") q = t_subject_messages.select().where( t_subject_messages.c.subject_id == subject_id).order_by( t_subject_messages.c.created_at.desc()).limit(limit).offset(offset) rows = DBSession.execute(q).fetchall() return { "messages": [{ "id": message["id"], "text": SubjectMessage.get_text(message), "is_read": message["is_read"], "created_at": message["created_at"] } for message in rows] }
def admin_tenant(environ, start_response): from gengine.app.admin import adminapp def admin_app(environ, start_response): #return HTTPSProxied(DebuggedApplication(adminapp.wsgi_app, True))(environ, start_response) return HTTPSProxied(adminapp.wsgi_app)(environ, start_response) def request_auth(environ, start_response): resp = Response() resp.status_code = 401 resp.www_authenticate = 'Basic realm="%s"' % ( "Gamification Engine Admin", ) return resp(environ, start_response) if not asbool(get_settings().get("enable_user_authentication", False)): return admin_app(environ, start_response) req = Request(environ) def _get_basicauth_credentials(request): authorization = request.headers.get("authorization", "") try: authmeth, auth = authorization.split(' ', 1) except ValueError: # not enough values to unpack return None if authmeth.lower() == 'basic': try: auth = base64.b64decode(auth.strip()).decode("UTF-8") except binascii.Error: # can't decode return None try: login, password = auth.split(':', 1) except ValueError: # not enough values to unpack return None return {'login': login, 'password': password} return None user = None cred = _get_basicauth_credentials(req) token = req.cookies.get("token", None) if token: tokenObj = DBSession.query(AuthToken).filter( AuthToken.token == token).first() user = None if tokenObj and tokenObj.valid_until < datetime.datetime.utcnow(): tokenObj.extend() if tokenObj: user = tokenObj.user if not user: if cred: user = DBSession.query(AuthUser).filter_by( email=cred["login"]).first() if not user or not user.verify_password(cred["password"]): return request_auth(environ, start_response) if user: j = t_auth_users_roles.join(t_auth_roles).join( t_auth_roles_permissions) q = select( [t_auth_roles_permissions.c.name], from_obj=j).where(t_auth_users_roles.c.auth_user_id == user.id) permissions = [r["name"] for r in DBSession.execute(q).fetchall()] if not perm_global_access_admin_ui in permissions: return request_auth(environ, start_response) else: token_s = user.get_or_create_token().token def start_response_with_headers(status, headers, exc_info=None): cookie = SimpleCookie() cookie['X-Auth-Token'] = token_s cookie['X-Auth-Token']['path'] = get_settings().get( "urlprefix", "").rstrip("/") + "/" headers.append( ('Set-Cookie', cookie['X-Auth-Token'].OutputString()), ) return start_response(status, headers, exc_info) return admin_app(environ, start_response_with_headers)
def add_or_update_subject(request): """add a subject and set its metadata""" subject_id = int(request.matchdict["subject_id"]) if asbool(get_settings().get("enable_user_authentication", False)): #ensure that the subject exists and we have the permission to update it may_update = request.has_perm( perm_global_manage_subjects ) or request.has_perm( perm_own_update_subject_infos) and request.subject.id == subject_id if not may_update: raise APIError(403, "forbidden", "You may not edit this subject.") #if not exists_by_expr(t_subjects,t_subjects.c.id==subject_id): # raise APIError(403, "forbidden", "The subject does not exist. As the user authentication is enabled, you need to create the AuthUser first.") lat = None if len(request.POST.get("lat", "")) > 0: lat = float(request.POST["lat"]) lon = None if len(request.POST.get("lon", "")) > 0: lon = float(request.POST["lon"]) friends = [] if len(request.POST.get("friends", "")) > 0: friends = [int(x) for x in request.POST["friends"].split(",")] groups = [] if len(request.POST.get("groups", "")) > 0: groups = [int(x) for x in request.POST["groups"].split(",")] timezone = "UTC" if len(request.POST.get("timezone", "")) > 0: timezone = request.POST["timezone"] if not valid_timezone(timezone): timezone = 'UTC' language = None if len(request.POST.get("language", "")) > 0: language = request.POST["language"] additional_public_data = {} if len(request.POST.get("additional_public_data", "")) > 0: try: additional_public_data = json.loads( request.POST["additional_public_data"]) except: additional_public_data = {} Subject.set_infos(subject_id=subject_id, lat=lat, lng=lon, timezone=timezone, language_id=language, additional_public_data=additional_public_data) Subject.set_relations(subject_id=subject_id, relation_ids=friends) Subject.set_parent_subjects(subject_id=subject_id, parent_subject_ids=groups) return {"status": "OK", "subject": Subject.full_output(subject_id)}
def add_or_update_user(request): """add a user and set its metadata""" user_id = int(request.matchdict["user_id"]) if asbool(get_settings().get("enable_user_authentication", False)): #ensure that the user exists and we have the permission to update it may_update = request.has_perm( perm_global_update_user_infos) or request.has_perm( perm_own_update_user_infos) and request.user.id == user_id if not may_update: raise APIError(403, "forbidden", "You may not edit this user.") #if not exists_by_expr(t_users,t_users.c.id==user_id): # raise APIError(403, "forbidden", "The user does not exist. As the user authentication is enabled, you need to create the AuthUser first.") lat = None if len(request.POST.get("lat", "")) > 0: lat = float(request.POST["lat"]) lon = None if len(request.POST.get("lon", "")) > 0: lon = float(request.POST["lon"]) friends = [] if len(request.POST.get("friends", "")) > 0: friends = [int(x) for x in request.POST["friends"].split(",")] groups = [] if len(request.POST.get("groups", "")) > 0: groups = [int(x) for x in request.POST["groups"].split(",")] timezone = "UTC" if len(request.POST.get("timezone", "")) > 0: timezone = request.POST["timezone"] if not valid_timezone(timezone): timezone = 'UTC' country = None if len(request.POST.get("country", "")) > 0: country = request.POST["country"] region = None if len(request.POST.get("region", "")) > 0: region = request.POST["region"] city = None if len(request.POST.get("city", "")) > 0: city = request.POST["city"] language = None if len(request.POST.get("language", "")) > 0: language = request.POST["language"] additional_public_data = {} if len(request.POST.get("additional_public_data", "")) > 0: try: additional_public_data = json.loads( request.POST["additional_public_data"]) except: additional_public_data = {} User.set_infos(user_id=user_id, lat=lat, lng=lon, timezone=timezone, country=country, region=region, city=city, language=language, friends=friends, groups=groups, additional_public_data=additional_public_data) return {"status": "OK", "user": User.full_output(user_id)}
def increase_value(request): """increase a value for the subject""" subject_id = int(request.matchdict["subject_id"]) try: value = float(request.POST["value"]) except: try: doc = request.json_body value = doc["value"] except: raise APIError(400, "invalid_value", "Invalid value provided") key = request.matchdict["key"] if ( "key" in request.matchdict and request.matchdict["key"] is not None) else "" variable_name = request.matchdict["variable_name"] subject = Subject.get_subject(subject_id) if not subject: raise APIError(404, "subject_not_found", "subject not found") variable = Variable.get_variable_by_name(variable_name) if not variable: raise APIError(404, "variable_not_found", "variable not found") if asbool(get_settings().get("enable_user_authentication", False)): if not AuthUser.may_increase(variable, request, subject_id): raise APIError( 403, "forbidden", "You may not increase the variable for this subject.") Value.increase_value(variable_name, subject["id"], value, key, at_datetime=dt_now()) try: achievement_history = int(request.GET["achievement_history"]) except: achievement_history = 2 output = _get_progress(achievements_for_subject=subject, requesting_subject=request.subject, achievement_history=achievement_history) output = copy.deepcopy(output) to_delete = list() for i in range(len(output["achievements"])): if len(output["achievements"][i]["new_levels"]) > 0: if "levels" in output["achievements"][i]: del output["achievements"][i]["levels"] if "priority" in output["achievements"][i]: del output["achievements"][i]["priority"] if "goals" in output["achievements"][i]: del output["achievements"][i]["goals"] else: to_delete.append(i) for i in sorted(to_delete, reverse=True): del output["achievements"][i] return output
def send_push_message(subject_id, text="", custom_payload={}, title="Gamification-Engine", android_text=None, ios_text=None): message_count = DBSession.execute( select([func.count("*").label("c")], from_obj=t_subject_messages).where( and_(t_subject_messages.c.subject_id == subject_id, t_subject_messages.c.is_read == False))).scalar() data = dict({"title": title, "badge": message_count}, **custom_payload) settings = get_settings() if not ios_text: ios_text = text if not android_text: android_text = text rows = DBSession.execute( select([t_subject_device.c.push_id, t_subject_device.c.device_os], from_obj=t_subject_device).distinct().where( t_subject_device.c.subject_id == subject_id)).fetchall() for device in rows: if "ios" in device.device_os.lower(): identifier = random.getrandbits(32) if custom_payload: payload = Payload(alert=ios_text, custom=data, badge=message_count, sound="default") else: payload = Payload(alert=ios_text, custom=data, badge=message_count, sound="default") log.debug("Sending Push message to User (ID: %s)", subject_id) if device.push_id.startswith("prod_"): get_prod_apns().gateway_server.send_notification( device.push_id[5:], payload, identifier=identifier) elif device.push_id.startswith("dev_"): get_dev_apns().gateway_server.send_notification( device.push_id[4:], payload, identifier=identifier) if "android" in device.device_os.lower(): log.debug("Sending Push message to User (ID: %s)", subject_id) push_id = lstrip_word(device.push_id, "dev_") push_id = lstrip_word(push_id, "prod_") response = get_gcm().json_request( registration_ids=[ push_id, ], data={ "message": android_text, "data": data, "title": title }, restricted_package_name=os.environ.get( "GCM_PACKAGE", settings.get("gcm.package", "")), priority='high', delay_while_idle=False) if response: gcm_feedback(response)