def main():
    try:
        app = SESSION.query(App).filter(App.name == "CloudControl").one()
        if app.status == "stop":
            app.start_time = datetime.datetime.now()
            app.end_time = None
            app.status = "running"
    except sqlalchemy.orm.exc.NoResultFound:
        app = App(
            name="CloudControl",
            start_time=datetime.datetime.now(),
            status="running",
            platform=1
        )
        SESSION.add(app)
    except sqlalchemy.orm.exc.MultipleResultsFound:
        pass

    SESSION.commit()
    ioloop.IOLoop.current().spawn_callback(get_code)
    yield generate_case()
    yield Q.join()

    app.end_time = datetime.datetime.now()
    app.status = "stop"
    global DONE_COUNT, CASE_COUNT
    DONE_COUNT = 0
    CASE_COUNT = 0
    SESSION.commit()
Пример #2
0
def _csv_to_db(csvfile):
    """Read a CSV file and create App models from row/fields.
    Store empty values as '' to avoid storing None which renders
    ugly in template and cannot be unicoded on export.
    We are not doing smart things like foreign keys to controlled vocabulary tables,
    nor converting string values to Integer, Boolean, Date, etc.
    """
    num_apps = 0
    warnings = []
    infos = []
    App.objects.all().delete()  # DANGER: Delete existing apps info
    reader = csv.DictReader(csvfile)
    for field in reader.fieldnames:
        if field not in MOGRIFIELDS.keys():
            msg = "Ignoring unrecognized field name '%s' for all rows in CSV" % field
            warnings.append(msg)
            logging.warning(msg)
    for rid, row in enumerate(reader):
        acronym = row["Acronym"].strip()
        version = row["Version Number"].strip()
        if acronym == "":
            msg = "Ignoring row=%d without Acronym" % rid
            warnings.append(msg)
            logging.warning(msg)
            continue
        if len(acronym) < 2:
            msg = "Ignoring row=%d with too-short Acronym=%s" % (rid, acronym)
            warnings.append(msg)
            logging.warning(msg)
            continue
        existing = App.objects.filter(acronym__iexact=acronym, version_number=version)
        if existing:
            msg = "Ignoring extant acronym=%s version=%s" % (acronym, version)
            warnigns.append(msg)
            logging.warning(msg)
            continue
        app = App()
        app.save()  # save for M2M
        for k, v in row.items():
            if k not in MOGRIFIELDS.keys():
                continue  # ignore unrecognized field names
            v = v.strip()
            try:
                setattr(app, MOGRIFIELDS[k], v)
            except (TypeError, ValidationError), e:
                logging.error("SETATTR: %s", e)
                import pdb

                pdb.set_trace()
        try:
            app.save()
        except (TypeError, ValidationError), e:
            logging.error("SAVE: %s", e)
            import pdb

            pdb.set_trace()
Пример #3
0
def populate_datastore():
    client_key_name1='client01'
    client1 = Client(key_name=client_key_name1, id='12345678', name='Organic Oranges LLC', domain=db.Link("http://client1.clickin-tech.appspot.com"))
    client1.put()
    
    client_key_name2='client02'
    client2 = Client(key_name=client_key_name2, id='87654321', name='Green Trees Inc.', domain=db.Link("http://client2.clickin-tech.appspot.com"))
    client2.put()
    
    admin_key_name1='admin001'
    admin1 = Client_User(key_name=admin_key_name1, client=client1, id='001002', name='Daniel Alves', 
                        email='*****@*****.**')
    admin1.put()
        
    admin_key_name2='admin002'
    admin2 = Client_User(key_name=admin_key_name2, client=client1, id='001005', name='Andres Iniesta', 
                        email='*****@*****.**')
    admin2.put()
        

    admin_key_name5='admin05'
    admin5 = Client_User(key_name=admin_key_name5, client=client2, id='0010011', name='Josep Guardiola', 
                        email='*****@*****.**')
    admin5.put()
        
    admin_key_name6='admin06'
    admin6 = Client_User(key_name=admin_key_name6, client=client2, id='0010016', name='Lionel Messi', 
                        email='*****@*****.**')
    admin6.put()
        
    #ClickIn People Search
    app_key_name1='app1'
    app1 = App(key_name=app_key_name1, client=client1, app_id='163185560402939', 
               api_key='807c2277abe596cfe542927858105306', 
               app_secret='aae6abb4d6bf0b41f066c387ab36e486',
               name = 'ClickIn People Search', 
               domain=db.Link("http://app1.client1.clickin-tech.appspot.com/"))
    app1.put()
        
    #Click In People Search 2
    app_key_name2='app2'
    app2 = App(key_name=app_key_name2, client=client1, app_id='114549068628127', 
               api_key='7f15ffb2b72ff6c4a6d08daebca21a52', 
               app_secret='61545bcd8a3d9fc6a8107eaed5cbe4de',
                   name = 'ClickIn People Search 2', 
                   domain=db.Link("http://app2.client1.clickin-tech.appspot.com/"))
    app2.put()
        
    #Cool Running App
    app_key_name3='app3'
    app3 = App(key_name=app_key_name3, client=client2, app_id='107411582680918', 
               api_key='7a55f39fb4e0371aad78e1bd8dd517af', 
               app_secret='c12b89b5f815cebe27636cd8c50a6264',
               name = 'Cool Running App', 
               domain=db.Link("http://app1.client2.clickin-tech.appspot.com/"))

    app3.put()      
Пример #4
0
def get_apps( *, page = '1' ):
    page_index = get_page_index( page )
    num = yield from App.findNumber( 'count(id)' )
    page = Page( num, page_index )
    if num == 0:
        apps = []
    else:
        apps = yield from App.findAll( orderBy = 'created_at desc', limit = ( page.offset, page.limit ) )  
    logging.info( 'Page: %s, BlogsNum: %s.' % ( page, len( apps ) ) )
    return {
        '__template__' : 'apps.html',
        'page' : page,
        'apps' : apps
    }
Пример #5
0
    def get(self):
        account_count = Account.all().count(1000)
        app_count = App.all().count(1000)

        html = """<?xml version="1.0" encoding="UTF-8"?>
        <root>
        	<item>
        		<value>%(app_count)d</value>
        		<text>Apps</text>
        	</item>
        	<item>
        		<value>0</value>
        		<text></text>
        	</item>
        	<item>
        		<value>%(account_count)d</value>
        		<text>Accounts</text>
        	</item>
        </root>
        """ % dict(
            account_count=account_count, app_count=app_count
        )

        #        return Response(html, content_type="text/xml")
        self.response.headers["Content-Type"] = "text/xml"
        self.response.write(html)
Пример #6
0
    def get(self, user, account, **kwargs):
        users_info = {}

        app_query = App.all()
        if not users.is_current_user_admin():
            app_query = app_query.filter("editors", account.key())
        apps = app_query.fetch(100)

        accounts_by_key = {}
        for acc in Account.get(set([app._created_by for app in apps] + [account.key()])):
            accounts_by_key[acc.key()] = acc

            users_info[acc.user.user_id()] = {
                "apps": [],
                "full_name": acc.full_name or "",
                "email": acc.user.email(),
                "created_at": time.mktime(acc.created_at.timetuple()),
            }

        for app in apps:
            users_info[accounts_by_key[app._created_by].user.user_id()]["apps"].append(
                {"id": app.key().id(), "body": app.body}
            )

        return render_json_response(
            self, {"users": users_info, "current_user": account.user.user_id() if account else None}
        )
Пример #7
0
    def clean_subdomain(self):
        subdomain = self.cleaned_data['subdomain']

        subdomain = App.provision_subdomain(subdomain)

        self.cleaned_data['subdomain'] = subdomain
        return subdomain
Пример #8
0
def app_complete(app_id):
    """
    游戏创建完成
    """
    db = g._db

    app = App.get_app(db, app_id)
    
    return render_template('app/complete.html', app=app)
Пример #9
0
def app_detail(appid):
    """
    store 详情

    """
    db = g._db
    app = App.get_app(db, appid)

    return render_template('app/detail.html', app=app)
Пример #10
0
    def delete(self, user, account, **kwargs):
        app_id = kwargs["app_id"]

        app = App.get_by_id(int(app_id))
        if app is None:
            return render_json_response(self, {"error": "app-not-found"})
        if account.key() not in app.editors:
            return render_json_response(self, {"error": "access-denied"})
        app.delete()
        return render_json_response(self, {"status": "ok"})
Пример #11
0
def app_index():
    """
    store 模块首页

    """
    uid = session['user']['id']
    store_id = session['user']['store_id']

    db = g._imdb
    allApps = App.get_apps(db, store_id)
    wxs = App.get_wxs(db, store_id)
    
    #移除wx公众号
    apps = []
    for app in allApps:
        r = [wx for wx in wxs if wx['id'] == app['id']]
        if not r:
            apps.append(app)

    return render_template('app/index.html', data={'list':apps})
Пример #12
0
 def get(self):
     admin = authorizedAdminClient()
     if admin:
         app_id = cgi.escape(self.request.get("app"))
         encoded_app_id = base64.b64encode(app_id)
         apps = App.all()
         apps.filter('app_id =', app_id)
         app = apps.get()
         self.render(u'app_menu', app=app, encoded_app_id=encoded_app_id)
     else:
         self.render(u'unauthorized', user=users.get_current_user(),
                     login_url=users.create_login_url("/"),
                     logout_url=users.create_logout_url("/"))
Пример #13
0
def api_new_app():
    try:
        file = request.files['file']
        app = App.from_file(file)
    except Exception as e:
        web.logger.error('%r', e)
        res = jsonify({'message': e.message})
        res.status_code = 400
        return res
    else:
        db.session.add(app)
        db.session.commit()
        return jsonify(simple_serialize(app))
Пример #14
0
    def get(self):
        account_count = Account.all().count(1000)
        app_count = App.all().count(1000)

        html = """
        <pre>
        Mockko statistics:

        Users:          %(account_count)d
        Applications:   %(app_count)d
        """ % dict(
            account_count=account_count, app_count=app_count
        )

        #        return Response(html, content_type="text/html")
        self.response.headers["Content-Type"] = "text/html"
        self.response.write(html)
Пример #15
0
def get_access_token(rds, db, wx_appid):
    access_token = WX.get_access_token(rds, wx_appid)
    if not access_token:
        app = App.get_wx(db, wx_appid)
        if not app:
            return None
        refresh_token = app['refresh_token']

        component_token = get_component_access_token(rds)
        if not component_token:
            return None

        wx = WXOpenAPI(APPID, APPSECRET, component_token)

        r = wx.refresh_auth(wx_appid, refresh_token)

        if r.get('errcode'):
            logging.error("refresh auto error:%s %s", 
                          r['errcode'], r['errmsg'])
            return None

        token = r['authorizer_access_token']
        expires = r['expires_in']
        authorizer_refresh_token = r['authorizer_refresh_token']

        #提前10分钟过期
        if expires > 20*60:
            expires = expires - 10*60

        if authorizer_refresh_token != refresh_token:
            logging.error("old refresh token:%s new refresh token:%s", 
                          refresh_token, authorizer_refresh_token)
        else:
            logging.debug("refresh token is unchanged")

        WX.set_access_token(rds, wx_appid, token, expires)
        access_token = token

    return access_token
Пример #16
0
    def post(self, user, account, **kwargs):
        app_id = kwargs["app_id"] if "app_id" in kwargs else "new"
        body_json = self.request.body
        body = json.loads(body_json)

        if "name" not in body:
            logging.exception(exception)
            self.response.set_status(400)
            self.response.write("Invalid JSON data")
        #            return BadRequest("Invalid JSON data")

        if app_id == "new":
            app = App(name=body["name"], created_by=account.key(), editors=[account.key()])
        else:
            app = App.get_by_id(int(app_id))
            if app is None:
                return render_json_response(self, {"error": "app-not-found"})
            if account.key() not in app.editors:
                return render_json_response(self, {"error": "access-denied"})
        app.name = body["name"]
        app.body = db.Text(body_json.decode("utf-8"))
        app.put()
        return render_json_response(self, {"id": app.key().id()})
Пример #17
0
def app_edit(appid):
    """
    创建游戏
    """
    app = App.get_app(g._db, appid)
    return render_template('app/edit.html', data={'game': app, 'method': 'edit'})
Пример #18
0
 def post(self):
     app = App.instance()
     app.total_posts += 1
     app.put()
Пример #19
0
 def get(self):
     app = App.instance()
     self.response.out.write(template.render('templates/main.html', locals()))
Пример #20
0
def handle_authorized(data):
    authorizer_appid = data.get('AuthorizerAppid')
    authorization_code = data.get('AuthorizationCode')
    code_expire = data.get('AuthorizationCodeExpiredTime')

    logging.debug("authorized appid:%s code:%s expire:%s", 
                  authorizer_appid, authorization_code, code_expire)

    rds = g.im_rds
    db = g._db
    auth_code = authorization_code
    store_id = 0

    component_token = get_component_access_token(rds)
    if not component_token:
        return "授权失败"

    wx = WXOpenAPI(APPID, APPSECRET, component_token)
    r = wx.request_auth(auth_code)
    if r:
        info = r['authorization_info']
        wx_appid = info['authorizer_appid']
        access_token = info['authorizer_access_token']
        expires_in = info['expires_in']
        #提前10分钟过期
        if expires_in > 20*60:
            expires_in = expires_in - 10*60

        refresh_token = info['authorizer_refresh_token']
        funcs = info['func_info']
        fids = []
        for f in funcs:
            fid = f['funcscope_category']['id']
            fids.append(fid)

        is_app = False
        AUTHORIZATION_MESSAGE = 1
        AUTHORIZATION_CONTACT = 19
        if AUTHORIZATION_MESSAGE in fids:
            #公众号
            is_app = False
        elif AUTHORIZATION_CONTACT in fids:
            #小程序
            is_app = True
        else:
            logging.warning("no message authorization")
            return "没有消息权限"

        app_info = wx.request_info(wx_appid)
        if not app_info:
            logging.warning("request app info fail")
            return "获取公众号信息失败"
        name = app_info['authorizer_info']['nick_name']
        gh_id = app_info['authorizer_info']['user_name']

        app = App.get_wx(db, wx_appid)
        if app:
            Client.update_wx(db, wx_appid, refresh_token, 1)
            if app['store_id'] != 0 and app['store_id'] != store_id:
                return "已被其它账号授权"
        else:
            App.create_wx(db, name, gh_id, wx_appid, refresh_token, store_id, is_app)
        WX.set_access_token(rds, wx_appid, access_token, expires_in)
        return "授权成功"
    else:
        return "获取令牌失败"
Пример #21
0
def auth_callback(uid):
    rds = g.im_rds
    db = g._db
    auth_code = request.args.get('auth_code')
    expires_in = request.args.get('expires_in')
    if not auth_code or not expires_in:
        return "非法调用"

    seller = Seller.get_seller(db, uid)
    store_id = seller['store_id']

    logging.debug("auth callback code:%s uid:%s store_id:%s", 
                  auth_code, uid, store_id)

    component_token = get_component_access_token(rds)
    if not component_token:
        return "授权失败"

    wx = WXOpenAPI(APPID, APPSECRET, component_token)
    r = wx.request_auth(auth_code)
    if r:
        info = r['authorization_info']
        logging.debug("auth callback info:%s", info)
        wx_appid = info['authorizer_appid']
        access_token = info['authorizer_access_token']
        expires_in = info['expires_in']
        #提前10分钟过期
        if expires_in > 20*60:
            expires_in = expires_in - 10*60

        refresh_token = info['authorizer_refresh_token']
        funcs = info['func_info']
        fids = []
        for f in funcs:
            fid = f['funcscope_category']['id']
            fids.append(fid)

        is_app = False
        AUTHORIZATION_MESSAGE = 1
        AUTHORIZATION_CONTACT = 19
        if AUTHORIZATION_MESSAGE in fids:
            #公众号
            is_app = False
        elif AUTHORIZATION_CONTACT in fids:
            #小程序
            is_app = True
        else:
            logging.warning("no message authorization")
            return "没有消息权限"

        app_info = wx.request_info(wx_appid)
        if not app_info:
            logging.warning("request app info fail")
            return "获取公众号信息失败"
        name = app_info['authorizer_info']['nick_name']
        gh_id = app_info['authorizer_info']['user_name']

        app = App.get_wx(db, wx_appid)
        if app:
            Client.update_wx(db, wx_appid, refresh_token, 1)
            if app['store_id'] != 0 and app['store_id'] != store_id:
                return "已被其它账号授权"
            if app['store_id'] == 0:
                App.set_store_id(db, app['id'], store_id)
        else:
            App.create_wx(db, name, gh_id, wx_appid, refresh_token, store_id, is_app)
        WX.set_access_token(rds, wx_appid, access_token, expires_in)
        return "授权成功"
    else:
        return "获取令牌失败"
Пример #22
0
def get_user(rds, db, gh_id, openid):
    now = int(time.time())
    u = WXUser.get_wx_user(rds, gh_id, openid)
    if not u:
        wx = App.get_wx_by_ghid(db, gh_id)
        if not wx:
            logging.error("invalid gh_id:%s", gh_id)
            return None

        store_id = wx['store_id']
        if not store_id:
            logging.error("can't find store id with gh_id:%s", gh_id)
            return None

        access_token = get_access_token(rds, db, wx['wx_app_id'])
        if not access_token:
            logging.error("can't get access token")
            return None

        mp = WXMPAPI(access_token)
        
        uid = WXUser.gen_id(rds)
        u = WXUser()
        u.gh_id = gh_id
        u.openid = openid
        u.appid = wx['appid']
        u.wx_appid = wx['wx_app_id']
        u.uid = uid
        u.store_id = store_id
        u.timestamp = now
        u.seller_id = 0
        WXUser.save_wx_user(rds, u)
        WXUser.bind_openid(rds, u.appid, u.uid, openid)
        logging.debug("bind openid:%s %s %s", u.appid, u.uid, openid)
        
        r = mp.get_user_by_openid(openid)
        if r.get('errcode'):
            logging.error("get user error:%s %s", 
                          r['errcode'], r['errmsg'])
        else:
            avatar = r.get('headimgurl', '')
            name = r.get('nickname', '')
            logging.debug("gh_id:%s openid:%s name:%s avatar:%s", gh_id, openid, name, avatar)
            WXUser.set_user_name(rds, u.appid, u.uid, name, avatar)
    elif now - u.timestamp > 4*3600:
        #更新用户信息
        wx = App.get_wx_by_ghid(db, gh_id)
        if not wx:
            logging.error("invalid gh_id:%s", gh_id)
            return None

        store_id = wx.get('store_id')
        if not store_id:
            logging.error("gh_id:%s is unauth", gh_id)
            return None
        
        appid = wx['appid']
        #切换到其它账号或者删除之后重新授权
        if u.store_id != store_id or u.appid != appid:
            logging.debug("store/app changed, gh_id:%s openid:%s store id:%s -> %s appid:%s -> %s",
                          gh_id, openid, u.store_id, store_id, u.appid, appid)
            #生成新的用户id
            uid = WXUser.gen_id(rds)
            u = WXUser()
            u.gh_id = gh_id
            u.openid = openid
            u.appid = wx['appid']
            u.wx_appid = wx['wx_app_id']
            u.uid = uid
            u.store_id = store_id
            u.timestamp = now
            u.seller_id = 0
            WXUser.save_wx_user(rds, u)
            WXUser.bind_openid(rds, u.appid, u.uid, openid)
            logging.debug("bind openid:%s %s %s", u.appid, u.uid, openid)

        if wx['is_app']:
            #小程序获取不到微信的用户信息
            WXUser.set_timestamp(rds, gh_id, openid, now)
        else:
            access_token = get_access_token(rds, db, wx['wx_app_id'])
            if not access_token:
                logging.error("can't get access token")
                return None
             
            mp = WXMPAPI(access_token)
            r = mp.get_user_by_openid(openid)
            if r.get('errcode'):
                logging.error("get user error:%s %s", 
                              r['errcode'], r['errmsg'])
            else:
                avatar = r.get('headimgurl', '')
                name = r.get('nickname', '')
                logging.debug("gh_id:%s openid:%s name:%s avatar:%s", gh_id, openid, name, avatar)
                WXUser.set_user_name(rds, u.appid, u.uid, name, avatar)
                WXUser.set_timestamp(rds, gh_id, openid, now)
        
    return u
Пример #23
0
    def get(self, app_id):

        # user = users.get_current_user()
        # if user is None:
        #     return render_json_response(self, { 'error': 'signed-out' })
        # else:
        #     account = Account.all().filter('user', user).get()
        #     if account is None:
        #         account = Account(user=user)
        #         account.put()
        app = App.get_by_id(int(app_id))
        if app is None:
            return render_json_response(self, {"error": "app-not-found"})
        # if account.key() not in app.editors:
        #     return render_json_response(self, { 'error': 'access-denied' })

        body_json = app.body
        content = json.loads(body_json)

        body = "\n".join([s["html"] for s in content["screens"]])
        body = body.replace('"static', '"/static')
        body = body.replace('"images', '"/images')

        html = """
        <!DOCTYPE html>
        <html>
          <head>
            <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
            <meta name="apple-mobile-web-app-capable" content="yes" />
            <meta name="apple-mobile-web-app-status-bar-style" content="default" />
            <link charset='utf-8' href='/static/iphone/iphone.css' media='screen' rel='stylesheet' title='no title' type='text/css' />
            <script charset='utf-8' src='/static/lib/jquery.js' type='text/javascript'></script>
            <style> .c-background { display: none; }</style>
            <script>
                jQuery(function($) {
                    $('.c-background:first').show();
                    $('.has-action').click(function() {
                        var action = $(this).attr('action');
                        var m;
                        if (m = action.match(/^screen:(.*)$/)) {
                            var screenId = "screen-" + m[1];
                            console.log("Jumping to #" + screenId);
                            $('.c-background').hide();
                            $('#' + screenId).show();
                        }
                    });
                });
            </script>
            <title>
              %(title)s
            </title>
          </head>
          <body class="run">
            %(content)s
          </body>
        </html>
""" % dict(
            title=content["name"], content=body
        )

        #        return Response(html, content_type="text/html")
        self.response.headers["Content-Type"] = "text/html"
        self.response.write(html)
Пример #24
0
def app_add_post():
    """
    创建应用
    """
    db = g._db

    store_id = session['user']['store_id']

    name = request.form.get('name')

    key = random_ascii_string(32)
    secret = random_ascii_string(32)

    android, ios = _get_clients()

    developer_id = 0

    db.begin()
    appid = App.gen_id(db)
    App.create_app(db, appid, name, developer_id, key, secret, store_id)

    if android:
        push_types = request.form.getlist('push_type')
        xinge_access_id = request.form.get('xinge_access_id', '')
        xinge_secret_key = request.form.get('xinge_secret_key', '')
        mi_appid = request.form.get('mi_appid', '')
        mi_secret_key = request.form.get('mi_secret_key', '')
        hw_appid = request.form.get('hw_appid', '')
        hw_secret_key = request.form.get('hw_secret_key', '')
        gcm_sender_id = request.form.get('gcm_sender_id', '')
        gcm_api_key = request.form.get('gcm_api_key', '')

        client_id = Client.gen_id(db)
        Client.create_client(db, client_id, appid, developer_id, PlatformType.ANDROID, android['platform_identity'])
        Client.create_android(db, client_id, xinge_access_id, xinge_secret_key, mi_appid, mi_secret_key, hw_appid, hw_secret_key, gcm_sender_id, gcm_api_key)


    if ios:
        sandbox_key_file = request.files.get('sandbox_key')
        if sandbox_key_file:
            filename = sandbox_key_file.filename
            ext = os.path.splitext(filename)[1]
            if ext == '.p12':
                sandbox_key = sandbox_key_file.read()
                sandbox_key_secret = request.form.get('sandbox_key_secret')
            else:
                sandbox_key = ""
                sandbox_key_secret = ""
        else:
            sandbox_key = ""
            sandbox_key_secret = ""

        production_key_file = request.files.get('production_key')
        if production_key_file:
            filename = production_key_file.filename
            ext = os.path.splitext(filename)[1]
            if ext == '.p12':
                production_key = production_key_file.read()
                production_key_secret = request.form.get('production_key_secret')
            else:
                production_key = ""
                production_key_secret = ""

        else:
            production_key = ""
            production_key_secret = ""

        client_id = Client.gen_id(db)
        Client.create_client(db, client_id, appid, developer_id, PlatformType.IOS, ios['platform_identity'])
        Client.create_ios(db, client_id, sandbox_key, sandbox_key_secret, production_key, production_key_secret)

        
    db.commit()

    return redirect(url_for('.app_complete', app_id=appid))
Пример #25
0
 def get(self):
     app_id = self.request.get("app")
     apps = App.all()
     apps.filter('app_id =', app_id)
     app = apps.get()
     self.render(u'permissions', app=app)
Пример #26
0
def update_all():
    for app in App.all():
        update_app(app)