Я действительно мало представляю, как работают ACL. Я знаю, это довольно круто и может сэкономить мне много времени и боли. Но в настоящее время я немного потерян. Все примеры для пирамиды используют обход. Я исключительно использую URL Dispatch. Я не уверен, что понимаю, как я могу построить древовидную структуру ресурсов.
Вот пример кода:
class QuestionFactory(object):
def __init__(self, request):
self.__acl__ = default[:]
self.uid = authenticated_userid(request)
self.qid = request.matchdict.get('id')
if self.qid:
self.question = request.db.questions.find_one({'_id': ObjectId(self.qid)})
if str(self.question.get('owner')) == self.uid:
self.__acl__.append((Allow, userid, 'view'))
Дело в том, что это работает. Но я должен определить новую фабрику для каждого типа ресурсов. Я не уверен, как мне узнать, к какому ресурсу я пытаюсь получить доступ через URL Dispatch и Factory. Я бы увидел что-то подобное
/accounts/{account} //Owners only but viewable by anyone
/messages/{message} //Owners only
/configs/{config} //Admin only
/pages/{page} //Admins only but viewable by anyone
Здесь сказано, что у меня будет такая структура
Root -\
+-- account
+-- message
+-- config
+-- page
У каждого из этих заводов есть свой специальный acl. Другое дело, что / account является главной страницей. У него нет идентификатора или чего-то еще. Также / account / new также является особым случаем. Это не идентификатор, а вид для создания нового элемента.
Я использую спокойный стиль с требованием GET / PUT / DELETE / POST. Я не совсем уверен, как я должен сопоставить URL-адрес с ресурсом и правильным ACL автоматически. Если я определю в своем корне специальную фабрику, как указано выше, проблем не будет.
редактировать
Я заставил его работать, за исключением некоторых вещей. Я, наконец, думаю, что понимаю, в чем цель траверса Например, у нас есть этот URL: / comments / 9494f0eda / new,
/ Комментарии / {комментарий} / * новый 1020 *
Нам может понадобиться узел в нашем дереве ресурсов или даже 3 узла.
Сначала RootFactory будет проверяться, а затем в соответствии с нашим обходом. Он получит атрибут комментариев RootFactory, затем «комментарий» фабрики комментариев и «новый» CommentFactory или самого объекта
Я не использую Фабрику как диктовку, как на примере Майкла
Это выглядит примерно так:
class RessourceFactory(object):
def __init__(self, parent, name):
self.__acl__ = []
self.__name__ = name
self.__parent__ = parent
self.uid = parent.uid
self.locale = parent.locale
self.db = parent.db
self.req = parent.req
Это мой базовый ресурсный объект. На каждом шаге он копирует информацию от родителя к новому дочернему элементу .. Я, конечно, мог бы всплывать в моем атрибуте .. context. parent ._ parent _. Uid, но это просто не так это здорово.
Причина, по которой я не использую атрибут dict. Я добавляю, чтобы он работал с
/ комментарии
По некоторым причинам он создал мою CommentFactory, но не вернул ее, так как не было необходимости в ключе.
Итак, моя корневая фабрика выглядит примерно так:
class RootFactory(object):
def __init__(self, request):
self.__acl__ = default[:]
self.req = request
self.db = request.db
self.uid = authenticated_userid(request)
self.locale = request.params.get('locale', 'en')
def __getitem__(self, key):
if key == 'questions':
return QuestionFactory(self, 'questions')
elif key == 'pages':
return PageFactory(self, 'pages')
elif key == 'configs':
return ConfigFactory(self, 'configs')
elif key == 'accounts':
return AccountFactory(self, 'accounts')
return self
если элемент не найден, RootFactory возвращает себя, если нет, возвращает новый Factory. Поскольку я основываю свой код на коде Майкла, для конструктора Factory есть второй параметр. Я не уверен, что сохраню это, так как QuestionFactory хорошо знает, как обрабатывать «вопросы», поэтому нет необходимости называть фабрику здесь. Он должен уже знать свое имя.
class QuestionFactory(RessourceFactory):
def __init__(self, parent, name):
RessourceFactory.__init__(self, parent, name)
self.__acl__.append((Allow, 'g:admin', 'view'))
self.__acl__.append((Allow, 'g:admin', 'edit'))
self.__acl__.append((Allow, 'g:admin', 'create'))
self.__acl__.append((Allow, 'g:admin', 'delete'))
self.__acl__.append((Allow, Everyone, 'create'))
def __getitem__(self, key):
if key=='read':
return self
self.qid = key
self.question = self.db.questions.find_one({'_id': ObjectId(self.qid)})
if str(self.question.get('owner')) == self.uid:
log.info('Allowd user %s' % self.uid)
self.__acl__.append((Allow, self.uid, 'view'))
self.__acl__.append((Allow, self.uid, 'edit'))
self.__acl__.append((Allow, self.uid, 'delete'))
return self
Так вот где почти вся логика пойдет. В init я установил acl, который будет работать для / questions, в getitem, который будет работать для / questions / {id} / *
Так как я возвращаю себя, любой getitem после этой RessourceFactory будет указывать на себя, если я не верну новую Фабрику для какого-то особого случая. Причина в том, что мой контекст - это не просто объект в базе данных или объект.
Мой контекст обрабатывает несколько вещей, таких как идентификатор пользователя, локаль и т. Д. ... когда ACL готов, у меня есть новый объект контекста, готовый к использованию. Это удаляет большую часть логики в представлениях.
Возможно, я мог бы установить события для запроса локали и идентификатора, но это действительно подходит здесь. Если мне нужно что-то новое, мне просто нужно отредактировать мои RootFactory и RessourceFactory, чтобы скопировать их на дочернюю фабрику.
Таким образом, если что-то должно измениться во всех представлениях, нет никакой избыточности вообще.