{"action":"created","issue":{"url":"https://api.github.com/repos/getsentry/sentry/issues/1342","labels_url":"https://api.github.com/repos/getsentry/sentry/issues/1342/labels{/name}","comments_url":"https://api.github.com/repos/getsentry/sentry/issues/1342/comments","events_url":"https://api.github.com/repos/getsentry/sentry/issues/1342/events","html_url":"https://github.com/getsentry/sentry/issues/1342","id":52326703,"number":1342,"title":"ACLs and Routing for Models","user":{"login":"dcramer","id":23610,"avatar_url":"https://avatars.githubusercontent.com/u/23610?v=3","gravatar_id":"","url":"https://api.github.com/users/dcramer","html_url":"https://github.com/dcramer","followers_url":"https://api.github.com/users/dcramer/followers","following_url":"https://api.github.com/users/dcramer/following{/other_user}","gists_url":"https://api.github.com/users/dcramer/gists{/gist_id}","starred_url":"https://api.github.com/users/dcramer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dcramer/subscriptions","organizations_url":"https://api.github.com/users/dcramer/orgs","repos_url":"https://api.github.com/users/dcramer/repos","events_url":"https://api.github.com/users/dcramer/events{/privacy}","received_events_url":"https://api.github.com/users/dcramer/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/getsentry/sentry/labels/Planned","name":"Planned","color":"207de5"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2014-12-18T05:19:41Z","updated_at":"2015-05-26T07:54:28Z","closed_at":"2015-05-26T07:54:28Z","body":"We plan to expand the base model with the following attributes:\r\n\r\n- User-level ACLs. You'd bind the queryset to an individual user or a generic user context (such as a superuser or anonymous user). The Phabricator project is a good example of inspiration for this. This will likely only do application level restrictions on ACLs, and be overwritten per relation.\r\n- Routing. Explicit hints in all querysets to aid in sharding.\r\n\r\nIf it makes sense, we will also provide basic shard management/creation/connection capabilities. It's likely this will be part of core, but it may not be required.\r\n\r\nThis may involve removing the Django ORM and augmenting it with something more explicit and simpler, but that's still up in the air.\r\n\r\n```python\r\nclass Model(partitions.Model):\r\n    project_id = partitions.ForeignKey('sentry.Project')\r\n\r\n    class Meta:\r\n        routing_key = ['project_id']\r\n\r\n    @classmethod\r\n    def has_perm(cls, item_list, user):\r\n        return True\r\n\r\ndef myview(request):\r\n    results = Model.query.as_user(request.user).filter(project_id=1)\r\n```\r\n\r\nRequirements:\r\n\r\n- The `as_user` method would be required before a queryset can be evaluated.\r\n- The `filter` method would require you to pass the values required per the `routing_key`.\r\n- The `has_perm` classmethod would be called with the results of the queryset. It would validate the entirety of the returned results and if any do not match a `False` value would cause the underying ORM to raise a permission exception.\r\n- We'd rely on the native DB router APIs, except they would be augmented to always have our routing hints.\r\n- An alternative to `filter`, we could call `route(project_id=1)` to bind the queryset to the correct connection. This would be especially hlepful if we build on top of the existing ORM so we can still use features like `.raw()`\r\n\r\nNice to haves:\r\n\r\n- The special `ForeignKey` class would work identical to a traditional ORM foreign key except it would not maintain constraints.\r\n"},"comment":{"url":"https://api.github.com/repos/getsentry/sentry/issues/comments/105432853","html_url":"https://github.com/getsentry/sentry/issues/1342#issuecomment-105432853","issue_url":"https://api.github.com/repos/getsentry/sentry/issues/1342","id":105432853,"user":{"login":"dcramer","id":23610,"avatar_url":"https://avatars.githubusercontent.com/u/23610?v=3","gravatar_id":"","url":"https://api.github.com/users/dcramer","html_url":"https://github.com/dcramer","followers_url":"https://api.github.com/users/dcramer/followers","following_url":"https://api.github.com/users/dcramer/following{/other_user}","gists_url":"https://api.github.com/users/dcramer/gists{/gist_id}","starred_url":"https://api.github.com/users/dcramer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dcramer/subscriptions","organizations_url":"https://api.github.com/users/dcramer/orgs","repos_url":"https://api.github.com/users/dcramer/repos","events_url":"https://api.github.com/users/dcramer/events{/privacy}","received_events_url":"https://api.github.com/users/dcramer/received_events","type":"User","site_admin":false},"created_at":"2015-05-26T07:54:28Z","updated_at":"2015-05-26T07:54:28Z","body":"We're likely scrapping SQL."}}