Updated Branches:
  refs/heads/master c7249d028 -> 221ada71f

Fauxton: Permissions settings for databases


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/724b3f2c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/724b3f2c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/724b3f2c

Branch: refs/heads/master
Commit: 724b3f2c1e162ddf8c40a1748a4c5b49cd163c85
Parents: c7249d0
Author: Garren Smith <[email protected]>
Authored: Tue Sep 24 13:31:01 2013 +0200
Committer: Garren Smith <[email protected]>
Committed: Fri Sep 27 11:27:26 2013 +0200

----------------------------------------------------------------------
 .gitignore                                      |   1 +
 src/fauxton/app/addons/permissions/base.js      |  25 +++
 src/fauxton/app/addons/permissions/resources.js |  70 +++++++
 src/fauxton/app/addons/permissions/routes.js    |  64 ++++++
 .../app/addons/permissions/templates/item.html  |  17 ++
 .../permissions/templates/permissions.html      |  15 ++
 .../addons/permissions/templates/section.html   |  37 ++++
 .../addons/permissions/tests/resourceSpec.js    |  51 +++++
 .../app/addons/permissions/tests/viewsSpec.js   | 159 +++++++++++++++
 src/fauxton/app/addons/permissions/views.js     | 199 +++++++++++++++++++
 src/fauxton/settings.json.default               |   1 +
 11 files changed, 639 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index a4798c9..58f992e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,6 +95,7 @@ src/fauxton/app/addons/*
 !src/fauxton/app/addons/contribute
 !src/fauxton/app/addons/auth
 !src/fauxton/app/addons/exampleAuth
+!src/fauxton/app/addons/permissions
 src/fauxton/settings.json*
 !src/fauxton/settings.json.default
 share/www/fauxton

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/base.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/base.js 
b/src/fauxton/app/addons/permissions/base.js
new file mode 100644
index 0000000..016ba1c
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/base.js
@@ -0,0 +1,25 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+define([
+       "app",
+       "api",
+       "addons/permissions/routes"
+],
+
+function(app, FauxtonAPI, Permissions) {
+
+  Permissions.initialize = function() {};
+
+  return Permissions;
+});
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/resources.js 
b/src/fauxton/app/addons/permissions/resources.js
new file mode 100644
index 0000000..66eaffd
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/resources.js
@@ -0,0 +1,70 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+define([
+       "app",
+       "api"
+],
+function (app, FauxtonAPI ) {
+  var Permissions = FauxtonAPI.addon();
+
+  Permissions.Security = Backbone.Model.extend({
+    defaults: {
+      admins: {
+        names: [],
+        roles: []
+      },
+
+      members: {
+        names: [],
+        roles: []
+      }
+    },
+
+    isNew: function () {
+      return false;
+    },
+
+    initialize: function (attrs, options) {
+      this.database = options.database;
+    },
+
+    url: function () {
+      return this.database.id + '/_security';
+    },
+
+    addItem: function (value, type, section) {
+      var sectionValues = this.get(section);
+
+      if (!sectionValues || !sectionValues[type]) { 
+        return {
+          error: true,
+          msg: 'Section ' + section + 'does not exist'
+        };
+      }
+
+      if (sectionValues[type].indexOf(value) > -1) { 
+        return {
+          error: true,
+          msg: 'Role/Name has already been added'
+        }; 
+      }
+
+      sectionValues[type].push(value);
+      return this.set(section, sectionValues);
+    }
+
+  });
+
+  return Permissions;
+});
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/routes.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/routes.js 
b/src/fauxton/app/addons/permissions/routes.js
new file mode 100644
index 0000000..f6c6587
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/routes.js
@@ -0,0 +1,64 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+define([
+       "app",
+       "api",
+       "modules/databases/base",
+       "addons/permissions/views"
+],
+function (app, FauxtonAPI, Databases, Permissions) {
+  
+  var PermissionsRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: 'one_pane',
+    selectedHeader: 'Databases',
+
+    routes: {
+      'database/:database/permissions': 'permissions'
+    },
+
+    initialize: function (route, masterLayout, options) {
+      var docOptions = app.getParams();
+      docOptions.include_docs = true;
+
+      this.databaseName = options[0];
+      this.database = new Databases.Model({id:this.databaseName});
+      this.security = new Permissions.Security(null, {
+        database: this.database
+      });
+    },
+
+    establish: function () {
+      return [this.database.fetch(), this.security.fetch()];
+    },
+
+    permissions: function () {
+      this.setView('#dashboard-content', new Permissions.Permissions({
+        database: this.database,
+        model: this.security
+      }));
+
+    },
+
+    crumbs: function () {
+      return [
+        {"name": "Databases", "link": "/_all_dbs"},
+        {"name": this.database.id, "link": 
Databases.databaseUrl(this.database)},
+        {"name": "Permissions", "link": "/permissions"}
+      ];
+    },
+
+  });
+  
+  Permissions.RouteObjects = [PermissionsRouteObject];
+  return Permissions;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/templates/item.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/templates/item.html 
b/src/fauxton/app/addons/permissions/templates/item.html
new file mode 100644
index 0000000..aa01d0b
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/templates/item.html
@@ -0,0 +1,17 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+<li> 
+<span> <%= item %> </span>
+<button type="button" style="float:none; margin-bottom:6px" 
class="close">&times;</button>
+</li> 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/templates/permissions.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/templates/permissions.html 
b/src/fauxton/app/addons/permissions/templates/permissions.html
new file mode 100644
index 0000000..d247425
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/templates/permissions.html
@@ -0,0 +1,15 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+<p>Each database contains lists of admins and members. Admins and members are 
each defined by names and roles, which are lists of strings.</p>
+<div id="sections"> </div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/templates/section.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/templates/section.html 
b/src/fauxton/app/addons/permissions/templates/section.html
new file mode 100644
index 0000000..102d857
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/templates/section.html
@@ -0,0 +1,37 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+<h1> <%= section %> </h1>
+<p id="help"> <%= help %> </p>
+
+<div class="row">
+  <div class="span6">
+    <h3> Names </h3>
+    <ul id="items-names"></ul>
+
+    <form class="permission-item-form form-inline">
+      <input data-section="<%= section %>" data-type="names" type="text" 
class="item input-small" placeholder="Add Name">
+      <input type="submit" class="btn" value="Add Name" >
+    </form>
+
+  </div>
+  <div class="span6">
+    <h3> Roles </h3>
+    <ul id="items-roles"></ul>
+
+    <form class="permission-item-form form-inline">
+      <input data-section="<%= section %>" data-type="roles" type="text" 
class="item input-small" placeholder="Add Role">
+      <input type="submit" class="btn" value="Add Role" >
+    </form>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/tests/resourceSpec.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/tests/resourceSpec.js 
b/src/fauxton/app/addons/permissions/tests/resourceSpec.js
new file mode 100644
index 0000000..f73687a
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/tests/resourceSpec.js
@@ -0,0 +1,51 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+define([
+       'api',
+       'addons/permissions/resources',
+      'testUtils'
+], function (FauxtonAPI, Models, testUtils) {
+  var assert = testUtils.assert;
+
+  describe('Permissions', function () {
+
+    describe('#addItem', function () {
+      var security;
+      
+      beforeEach(function () {
+        security = new Models.Security(null, {database: 'fakedb'});
+      });
+
+      it('Should add value to section', function () {
+
+        security.addItem('_user', 'names', 'admins');
+        assert.equal(security.get('admins').names[0], '_user');
+      });
+
+      it('Should handle incorrect type', function () {
+        security.addItem('_user', 'asdasd', 'admins');
+      });
+
+      it('Should handle incorrect section', function () {
+        security.addItem('_user', 'names', 'Asdasd');
+      });
+
+      it('Should reject duplicates', function () {
+        security.addItem('_user', 'names', 'admins');
+        security.addItem('_user', 'names', 'admins');
+        assert.equal(security.get('admins').names.length, 1);
+      });
+    });
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/tests/viewsSpec.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/tests/viewsSpec.js 
b/src/fauxton/app/addons/permissions/tests/viewsSpec.js
new file mode 100644
index 0000000..e5330c0
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/tests/viewsSpec.js
@@ -0,0 +1,159 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+define([
+       'api',
+       'addons/permissions/views',
+       'addons/permissions/resources',
+       'testUtils'
+], function (FauxtonAPI, Views, Models, testUtils) {
+  var assert = testUtils.assert,
+  ViewSandbox = testUtils.ViewSandbox;
+
+  describe('Permission View', function () {
+
+    beforeEach(function () {
+      security = new Models.Security({'admins': {
+        'names': ['_user'],
+        'roles': []
+      }
+      }, {database: 'fakedb'});
+
+      section = new Views.Permissions({
+        database: 'fakedb',
+        model: security
+      });
+
+      viewSandbox = new ViewSandbox();
+      viewSandbox.renderView(section); 
+    });
+
+    afterEach(function () {
+      viewSandbox.remove();
+    });
+
+    describe('itemRemoved', function () {
+
+      it('Should set model', function () {
+        var saveMock = sinon.spy(security, 'set');
+        Views.events.trigger('itemRemoved');
+
+        assert.ok(saveMock.calledOnce);
+        var args = saveMock.args; 
+        assert.deepEqual(args[0][0], 
{"admins":{"names":["_user"],"roles":[]},"members":{"names":[],"roles":[]}});
+      });
+
+      it('Should save model', function () {
+        var saveMock = sinon.spy(security, 'save');
+        Views.events.trigger('itemRemoved');
+
+        assert.ok(saveMock.calledOnce);
+      });
+    });
+
+  });
+
+  describe('PermissionsSection', function () {
+    var section, security;
+
+    beforeEach(function () {
+      security = new Models.Security({'admins': {
+        'names': ['_user'],
+        'roles': []
+      }
+      }, {database: 'fakedb'});
+
+      section = new Views.PermissionSection({
+        section: 'admins',
+        model: security
+      });
+
+      viewSandbox = new ViewSandbox();
+      viewSandbox.renderView(section); 
+    });
+
+    afterEach(function () {
+      viewSandbox.remove();
+    });
+
+    describe('#discardRemovedViews', function () {
+      it('Should not filter out active views', function () {
+        section.discardRemovedViews();
+
+        assert.equal(section.nameViews.length, 1);
+
+      });
+
+      it('Should filter out removed views', function () {
+        section.nameViews[0].removed = true;
+        section.discardRemovedViews();
+
+        assert.equal(section.nameViews.length, 0);
+
+      });
+
+    });
+
+    describe('#getItemFromView', function () {
+
+      it('Should return item list', function () {
+        var items = section.getItemFromView(section.nameViews);
+
+        assert.deepEqual(items, ['_user']);
+      });
+
+    });
+
+    describe('#addItems', function () {
+
+      it('Should add item to model', function () {
+        //todo add a test here
+
+      });
+
+    });
+
+  });
+
+  describe('PermissionItem', function () {
+    var item;
+
+    beforeEach(function () {
+      item = new Views.PermissionItem({
+        item: '_user'
+      });
+
+      viewSandbox = new ViewSandbox();
+      viewSandbox.renderView(item); 
+    });
+
+    afterEach(function () {
+      viewSandbox.remove();
+    });
+
+    it('should trigger event on remove item', function () {
+      var eventSpy = sinon.spy();
+
+      Views.events.on('itemRemoved', eventSpy);
+
+      item.$('.close').click();
+      
+      assert.ok(eventSpy.calledOnce); 
+    });
+
+    it('should set removed to true', function () {
+      item.$('.close').click();
+      
+      assert.ok(item.removed); 
+    });
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/app/addons/permissions/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/permissions/views.js 
b/src/fauxton/app/addons/permissions/views.js
new file mode 100644
index 0000000..4c2987b
--- /dev/null
+++ b/src/fauxton/app/addons/permissions/views.js
@@ -0,0 +1,199 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy 
of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations 
under
+// the License.
+
+define([
+       "app",
+       "api",
+       "addons/permissions/resources"
+],
+function (app, FauxtonAPI, Permissions ) {
+  var events = {};
+  Permissions.events = _.extend(events, Backbone.Events);
+
+  Permissions.Permissions = FauxtonAPI.View.extend({
+    template: "addons/permissions/templates/permissions",
+
+    initialize: function (options) {
+      this.database = options.database;
+      this.listenTo(Permissions.events, 'itemRemoved', this.itemRemoved);
+    },
+
+    itemRemoved: function (event) {
+      this.model.set({
+        admins: this.adminsView.items(),
+        members: this.membersView.items()
+      });
+
+      this.model.save().then(function () {
+        FauxtonAPI.addNotification({
+          msg: 'Database permissions has been updated.'
+        });
+        }, function (xhr) {
+        FauxtonAPI.addNotification({
+          msg: 'Could not update permissions - reason: ' + xhr.responseText,
+          type: 'error'
+        });
+      });
+    },
+
+    beforeRender: function () {
+      this.adminsView = this.insertView('#sections', new 
Permissions.PermissionSection({
+        model: this.model,
+        section: 'admins',
+        help: 'Database admins can update design documents and edit the admin 
and member lists.'
+      }));
+
+      this.membersView = this.insertView('#sections', new 
Permissions.PermissionSection({
+        model: this.model,
+        section: 'members',
+        help: 'Database members can access the database. If no members are 
defined, the database is public.'
+      }));
+    },
+
+    serialize: function () {
+      return {
+        databaseName: this.database.id,
+      };
+    }
+  });
+
+  Permissions.PermissionSection = FauxtonAPI.View.extend({
+    template: "addons/permissions/templates/section",
+    initialize: function (options) {
+      this.section = options.section;
+      this.help = options.help;
+    },
+
+    events: {
+      "submit .permission-item-form": "addItem",
+      'click .close': "removeItem"
+    },
+
+    beforeRender: function () {
+      var section = this.model.get(this.section);
+      
+      this.nameViews = [];
+      this.roleViews = [];
+
+      _.each(section.names, function (name) {
+        var nameView = this.insertView('#items-names', new 
Permissions.PermissionItem({
+          item: name,
+        }));
+        this.nameViews.push(nameView);
+      }, this);
+
+      _.each(section.roles, function (role) {
+        var roleView = this.insertView('#items-roles', new 
Permissions.PermissionItem({
+          item: role,
+        }));
+        this.roleViews.push(roleView);
+      }, this);
+    },
+
+    getItemFromView: function (viewList) {
+      return _.map(viewList, function (view) {
+        return view.item;
+      });
+    },
+
+    discardRemovedViews: function () {
+      this.nameViews = _.filter(this.nameViews, function (view) {
+        return !view.removed; 
+      });
+
+      this.roleViews = _.filter(this.roleViews, function (view) {
+        return !view.removed; 
+      });
+    },
+
+    items: function () {
+      this.discardRemovedViews();
+
+      return  {
+        names: this.getItemFromView(this.nameViews),
+        roles: this.getItemFromView(this.roleViews)
+      };
+    },
+
+    addItem: function (event) {
+      event.preventDefault();
+      var $item = this.$(event.currentTarget).find('.item'),
+          value = $item.val(),
+          section = $item.data('section'),
+          type = $item.data('type'),
+          that = this;
+
+      var resp = this.model.addItem(value, type, section);
+
+      if (resp && resp.error) {
+        return FauxtonAPI.addNotification({
+          msg: resp.msg,
+          type: 'error'
+        });
+      }
+
+      this.model.save().then(function () {
+        that.render();
+        FauxtonAPI.addNotification({
+          msg: 'Database permissions has been updated.'
+        });
+      }, function (xhr) {
+        FauxtonAPI.addNotification({
+          msg: 'Could not update permissions - reason: ' + xhr.responseText,
+          type: 'error'
+        });
+      });
+    },
+
+    serialize: function () {
+      return {
+        section: this.section,
+        help: this.help
+      };
+    }
+
+  });
+
+  Permissions.PermissionItem = FauxtonAPI.View.extend({
+    template: "addons/permissions/templates/item",
+    initialize: function (options) {
+      this.item = options.item;
+      this.viewsList = options.viewsList;
+    },
+
+    events: {
+      'click .close': "removeItem"
+    },
+
+    removeItem: function (event) {
+      var that = this;
+      event.preventDefault();
+      
+      this.removed = true;
+      Permissions.events.trigger('itemRemoved');
+
+      this.$el.hide('fast', function () {
+        that.remove();
+      });
+    },
+
+
+    serialize: function () {
+      return {
+        item: this.item
+      };
+    }
+
+  });
+
+  return Permissions;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/724b3f2c/src/fauxton/settings.json.default
----------------------------------------------------------------------
diff --git a/src/fauxton/settings.json.default 
b/src/fauxton/settings.json.default
index 81cb4cb..30088f0 100644
--- a/src/fauxton/settings.json.default
+++ b/src/fauxton/settings.json.default
@@ -6,6 +6,7 @@
   { "name": "stats" },
   { "name":  "replication" },
   { "name": "contribute" },
+  { "name": "permissions" },
   { "name": "auth" }
   ],
     "template": {

Reply via email to