瀏覽代碼

Added Models for groups

Raghav Arora 6 年之前
父節點
當前提交
26b7e81575
共有 4 個文件被更改,包括 134 次插入1 次删除
  1. 66 0
      migrations/versions/5319c9f4b7bc_.py
  2. 2 0
      nova/__init__.py
  3. 24 0
      nova/models.py
  4. 42 1
      nova/resources.py

+ 66 - 0
migrations/versions/5319c9f4b7bc_.py

@@ -0,0 +1,66 @@
+"""empty message
+
+Revision ID: 5319c9f4b7bc
+Revises: c84b6cdc4e99
+Create Date: 2017-09-22 17:09:35.838584
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '5319c9f4b7bc'
+down_revision = 'c84b6cdc4e99'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+
+    naming_convention = {
+        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
+    }
+    
+    op.create_table('groups',
+    sa.Column('id', sa.Integer(), nullable=False),
+    sa.Column('name', sa.String(), nullable=True),
+    sa.Column('description', sa.String(), nullable=True),
+    sa.PrimaryKeyConstraint('id')
+    )
+    op.create_table('memberships',
+    sa.Column('id', sa.Integer(), nullable=False),
+    sa.Column('user_id', sa.Integer(), nullable=True),
+    sa.Column('group_id', sa.Integer(), nullable=True),
+    sa.Column('is_creator', sa.Boolean(), nullable=True),
+    sa.Column('is_admin', sa.Boolean(), nullable=True),
+    sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
+    sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
+    sa.PrimaryKeyConstraint('id')
+    )
+    
+    with op.batch_alter_table(u'access_requests', naming_convention=naming_convention, schema=None) as batch_op:
+        batch_op.add_column(sa.Column('group_id', sa.Integer(), nullable=True))
+        batch_op.create_foreign_key('fk_access_requests_group_id_groups', 'groups', ['group_id'], ['id'])
+
+    with op.batch_alter_table(u'direct_access', naming_convention=naming_convention, schema=None) as batch_op:
+        batch_op.add_column(sa.Column('group_id', sa.Integer(), nullable=True))
+        batch_op.create_foreign_key('fk_direct_access_group_id_groups', 'groups', ['group_id'], ['id'])
+
+    # ### end Alembic commands ###
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    naming_convention = {
+        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
+    }
+    with op.batch_alter_table(u'direct_access', naming_convention=naming_convention, schema=None) as batch_op:
+        batch_op.drop_constraint('fk_direct_access_group_id_groups', type_='foreignkey')
+        batch_op.drop_column('group_id')
+
+    with op.batch_alter_table(u'access_requests', schema=None) as batch_op:
+        batch_op.drop_constraint('fk_access_requests_group_id_groups', type_='foreignkey')
+        batch_op.drop_column('group_id')
+
+    op.drop_table('memberships')
+    op.drop_table('groups')
+    # ### end Alembic commands ###

+ 2 - 0
nova/__init__.py

@@ -78,6 +78,8 @@ errors = {
 }
 
 api = Api(app, errors=errors)
+api.add_resource(resources.Groups, '/api/groups')
+api.add_resource(resources.Group, '/api/groups/<group_id>')
 api.add_resource(resources.Datasets, '/api/datasets')
 api.add_resource(resources.Dataset, '/api/datasets/<owner>/<dataset>')
 api.add_resource(resources.DeriveDataset, '/api/datasets/<owner>/<dataset>/derive')

+ 24 - 0
nova/models.py

@@ -81,6 +81,26 @@ class Collection(db.Model):
     def __repr__(self):
         return '<Collection(name={})>'.format(self.name)
 
+class Group(db.Model):
+    __tablename__ = 'groups'
+
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String)
+    description = db.Column(db.String)
+
+    memberships = db.relationship('Memberships', cascade='all, delete, delete-orphan')
+
+class Membership(db.Model):
+    __tablename__ = 'memberships'
+
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+    group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
+    is_creator = db.Column(db.Boolean, default=False)
+    is_admin = db.Column(db.Boolean, default=False)
+
+    user = db.relationship('User')
+    group = db.relationship('Group')
 
 class Dataset(db.Model):
 
@@ -381,6 +401,7 @@ class AccessRequest(db.Model):
 
     id = db.Column(db.Integer,  primary_key=True)
     user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+    group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
     dataset_id = db.Column(db.Integer, db.ForeignKey('datasets.id'))
     can_read = db.Column(db.Boolean, default=False)
     can_interact = db.Column(db.Boolean, default=False)
@@ -389,6 +410,7 @@ class AccessRequest(db.Model):
     created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
 
     user = db.relationship('User')
+    usergroup = db.relationship('Group')
     dataset = db.relationship('Dataset')
 
     def __repr__(self):
@@ -401,12 +423,14 @@ class DirectAccess(db.Model):
 
     id = db.Column(db.Integer,  primary_key=True)
     user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+    group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
     dataset_id = db.Column(db.Integer, db.ForeignKey('datasets.id'))
     can_read = db.Column(db.Boolean, default=False)
     can_interact = db.Column(db.Boolean, default=False)
     can_fork = db.Column(db.Boolean, default=False)
 
     user = db.relationship('User')
+    usergroup = db.relationship('Group')
     dataset = db.relationship('Dataset')
 
 

+ 42 - 1
nova/resources.py

@@ -64,6 +64,47 @@ class Service(Resource):
         del services[name]
 
 
+class Groups(Resource):
+    method_decorators = [authenticate]
+    def get(self, user=None):
+        parser = reqparse.RequestParser()
+        parser.add_argument('filter', type=str, required=False)
+        args = parser.parse_args()
+        query = db.session.query(models.Group)
+        if args.filter is 'me':
+            query = query.join(models.Membership).\
+            filter(models.Membership.user == user)
+        return [g.to_dict() for g in query.all()]
+
+    def post(self, user=None):
+        payload = request.get_json()
+        desc = payload['description'] if payload['description'] else ''
+        if payload['name']:
+            newgroup = models.Group(name=payload['name'], description=desc)
+            membership = models.Membership(user=user, group=newgroup,
+                                           is_creator=True, is_admin=False)
+            db.session.add_all([group, membership])
+            db.session.commit()
+            return 'Created', 201
+        abort(402)
+
+
+class Group(Resource):
+    method_decorators = [authenticate]
+    def get(self, group_id, user=None):
+        return db.session.query(models.Group).\
+            filter(models.Group.id == group_id).first().to_dict()
+
+    def put(self, group_id, user=None):
+        group, membership = db.session.query(models.Group, models.Membership).\
+            filter(models.Group.id == group_id).first()
+        if not membership:
+            membership = models.Membership(group=group, user=user)
+            db.session.add(membership)
+            db.session.commit()
+            return 200
+
+
 class Datasets(Resource):
     method_decorators = [authenticate]
 
@@ -137,7 +178,7 @@ class Dataset(Resource):
     def patch(self, owner, dataset, user=None):
         payload = request.get_json()
         if user.name != owner:
-            abort(403, "PUT forbidden from this user for this dataset")
+            abort(403, "PATCH forbidden from this user for this dataset")
         dataset = db.session.query(models.Dataset).\
                 filter(models.Permission.owner == user).\
                 filter(func.lower(models.Dataset.name) == func.lower(dataset)).\