2013-05-28 59 views
1

我正在尋找一些與我的應用程序的幫助。這裏的示例代碼第一(約2k行剝離下來...),我會盡量解釋一下我在尋找更高版本:ndb模型,裝飾器,嵌套函數

from google.appengine.ext import ndb 
import webapp2 
import json 

class User(ndb.Model): 
    company_    = ndb.KeyProperty(repeated=True) 

    @property 
    def company(self): 
    return {} if not self.company_ else self.company_ 

    @company.setter 
    def company(self, value): 
    if value: 
     self.company_ = self.company_.expand(value) if self.company_ else [value] 
    else: 
     self.company_ = [] 
    self.put() 

class Company(ndb.Model): 
    administrator   = ndb.KeyProperty(kind=User, repeated=True) 
    manager    = ndb.KeyProperty(kind=User, repeated=True) 

    # FAKE decorator 
    @staticmethod 
    def administrator(handler): 
    def check_requirements(self, *a, **kw): 
     if True: 
     return 
     else: 
     return handler(self, *a, **kw) 
    return check_requirements 

class BaseHandler(webapp2.RequestHandler): 
    def jwrite(self, **kw): 
    return self.response.out.write(json.dumps(kw)) 

class require(BaseHandler): 
    @staticmethod 
    def login(handler): 
    def check_requirements(self, *a, **kw): 
     if not self.auth.get_user_by_session(): 
     self.redirect('/', abort=True) 
     else: 
     return handler(self, *a, **kw) 
    return check_requirements 

class ApiHandler(BaseHandler): 
    @require.login 
    def post(self, model, action, key=''): 
    method = '_post_%s' % model 
    try: 
     getattr(self, method)(action, key) 
    except Exception as error: 
     return self.jwrite(error = error) 

    def _post_company(self, action, key): 

    if action == 'create': 
     data = dict(self.request.POST) 
     """ Company.create(data) method: 
      Populates Company instance with POST data. 
      Assigns first user that created the company 
      both administrator and manager roles. 
     """ 
     key_ = Company.create(data) 
     if key_: 
     self.user.company = key_ 
     return 

    elif action == 'delete': 

     @Company.administrator 
     def delete_all_user_companies(self): 
     ndb.delete_multi(self.user.company) 
     self.user.company = None 
     return 

     companies = ndb.get_multi(self.user.company) 
     if self.user.key in map(lambda c: c.administrator, companies): 
     delete_all_user_companies(self) 

    elif action == 'update': 

     @Company.manager 
     def update_company(self, key): 
     data = dict(self.request.POST) 
     """ Company.update(key, data) method: 
      Populates Company instance with POST data 
     """ 
     key_ = Company.update(key, data) 
     if key_: 
      return 

     company = ndb.Key(Company, key).get() 
     if self.user.key in company.manager.extend(company.administrator): 
     update_company(self) 

正如你所看到的,我有用戶和公司的模型。用戶可以有多個公司,公司可以有多個用戶,可以是管理員或經理。你會注意到一些裝飾和嵌套功能 - 其中大多數是假的(;但這就是我正在尋找...

我在做基本的登錄檢查@ require.login裝飾(我'我把它放在單獨的類中,只是因爲它在代碼中看起來更乾淨 - @ require.login vs @ BaseHandler.require_login)。我用它「保護」了API的post方法,現在我需要對角色進行額外的檢查 - 管理員可以做一些管理者不能做的事情,我需要在其他幾個地方做這個檢查,所以我認爲這將是一個裝飾器功能的好地方,但我不知道如何編寫它們。 :

  1. 這個裝飾器會是個好地方嗎?我應該把它放在公司類還是ApiHandler類的某個地方?我的第一個直覺是把它放在公司類,但我不知道如何處理範圍 - 我需要在那裏得到用戶實例(self.user.company列表)...

  2. 接下來的事情是經理裝飾者。我怎樣寫這個作爲裝飾:

    company = ndb.Key(Company, key).get() 
        if self.user.key in company.manager.extend(company.administrator): 
        update_company(self) 
    

    ,並以此爲@ Company.manager@ requre.manager,根據不同的答案,我的第一個問題?

  3. 管理員這一點更復雜的另一種裝飾 - 我要檢查,如果用戶是管理員爲他的所有公司,並刪除那些他在哪裏,同時保持者,他是不是:

    companies = ndb.get_multi(self.user.company) 
        if self.user.key in map(lambda c: c.administrator, companies): 
        delete_all_user_companies(self) 
    

    我甚至不確定這個map()函數是否正確,如果代碼可以工作,還沒有嘗試它 - 現在只是一個僞代碼佔位符...

  4. 最後一個問題:應該我關心POST請求黑客行爲?根據上面的示例代碼,是否有可能某些用戶可以自定義POST請求並刪除或更新不屬於他的公司? !

任何幫助,意見或見解,將不勝感激(;感謝

回答

3

我相信我已經解決了這個:

from google.appengine.ext import ndb 
import webapp2 
import json 

class User(ndb.Model): 
    company_    = ndb.KeyProperty(repeated=True) 

    @property 
    def company(self): 
    return {} if not self.company_ else self.company_ 

    @company.setter 
    def company(self, value): 
    if value: 
     # self.company_ = self.company_.expand(value) if self.company_ else [value] 
     # Lists mutate when expanded. Code above was returning None 
     self.company_ = self.company_ + [value] if self.company_ else [value] 
    else: 
     self.company_ = [] 
    self.put() 

class Company(ndb.Model): 
    administrator   = ndb.KeyProperty(kind=User, repeated=True) 
    manager    = ndb.KeyProperty(kind=User, repeated=True) 

class BaseHandler(webapp2.RequestHandler): 
    def jwrite(self, **kw): 
    return self.response.out.write(json.dumps(kw)) 

class require(BaseHandler): 
    @staticmethod 
    def login(handler): 
    def check_requirements(self, *a, **kw): 
     if not self.auth.get_user_by_session(): 
     self.redirect('/', abort=True) 
     else: 
     return handler(self, *a, **kw) 
    return check_requirements 

class role(BaseHandler): 
    @staticmethod 
    def administrator(handler): 
    def check_requirements(self, *a, **kw): 
     # I didn't care much about optimizing queries 
     # since this isn't frequent operation. 
     # For more frequent calls, I'd consider projections. 
     companies = ndb.get_multi(*a) 
     # Next lines checks if current user is administrator 
     # for all companies passed to the function 
     if not self.user.key in reduce(lambda x, y: x if x != y else y, map(lambda c: c.administrator, companies)): 
     return self.jwrite(error = 'Permission denied. Administrator required.') 
     else: 
     return handler(self, *a, **kw) 
    return check_requirements 

    @staticmethod 
    def manager(handler): 
    def check_requirements(self, *a, **kw): 
     companies = ndb.get_multi(*a) 
     # Next lines checks if current user is manager 
     # or administrator (since admin has higher privileges) 
     # for all companies passed to the function 
     if not self.user.key in reduce(lambda x, y: x if x != y else y, map(lambda c: c.manager + c.administrator, companies)): 
     return self.jwrite(error = 'Permission denied. Manager or Administrator required.') 
     else: 
     return handler(self, *a, **kw) 
    return check_requirements 

class ApiHandler(BaseHandler): 
    @require.login 
    def post(self, model, action, key=''): 
    method = '_post_%s' % model 
    try: 
     getattr(self, method)(action, key) 
    except Exception as error: 
     return self.jwrite(error = error) 

    def _post_company(self, action, key): 

    if action == 'create': 
     data = dict(self.request.POST) 
     """ Company.create(data) method: 
      Populates Company instance with POST data. 
      Assigns first user that created the company 
      both administrator and manager roles. 
     """ 
     key_ = Company.create(data) 
     if key_: 
     self.user.company = key_ 
     return 

    elif action == 'delete': 

     @role.administrator 
     def delete_all_user_companies(self, *a): 
     ndb.delete_multi(*a) 
     self.user.company = None 
     return 

     delete_all_user_companies(self, self.user.company) 

    elif action == 'update': 

     @role.manager 
     def update_company(self, *a): 
     data = dict(self.request.POST) 
     """ Company.update(key, data) method: 
      Populates Company instance with POST data 
     """ 
     key_ = Company.update(key, data) 
     if key_: 
      return 

     update_company(self, ndb.Key(Company, key)) 

,並回答了我自己的問題:

  1. 我在公司類裏面命名時遇到了問題 - 有屬性管理員和裝飾器都有相同的名稱,於是我將deco爲了方便起見,將API轉換爲新的類(角色)。當我編寫裝飾器時,我意識到我可以將它們用於任何其他模型(包括經理和管理員字段),所以我認爲這是一個很好的調用(但是,寫入裝飾器需要一些時間並試驗映射和減少數組,但我已經設法解決了這個問題,我不確定是否需要將參數傳遞給裝飾器,也許我應該在裝飾器之外進行查詢,或者將匹配項傳遞給處理器函數,我將不得不考慮它。 。

  2. ...並刪除那些他在哪裏,同時保持者,他是不是管理員這就是爲什麼我做內部裝飾疑問擺在首位,但仍然不知道,如果它的智能(。

  3. 我仍然可以使用這個答案。

希望這可以幫助別人......

+0

沒關係接受你自己的問題! –