예제 #1
0
 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()
             }
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
 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
예제 #6
0
            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)
예제 #7
0
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
예제 #8
0
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"}
예제 #9
0
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
예제 #10
0
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"}
예제 #11
0
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"}
예제 #12
0
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"}
예제 #13
0
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]
    }
예제 #14
0
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)
예제 #15
0
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)}
예제 #16
0
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)}
예제 #17
0
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
예제 #18
0
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)