refactored javascript and template files into components

pull/306/merge
Justin Richer 2013-02-13 10:12:31 -05:00
parent 137e5e5ca1
commit 991f37a1e6
17 changed files with 2277 additions and 2267 deletions

View File

@ -5,9 +5,9 @@
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="resources/bootstrap2/js/bootstrap.js"></script>
<script type="text/javascript" src="resources/js/underscore.js"></script>
<script type="text/javascript" src="resources/js/backbone.js"></script>
<script type="text/javascript" src="resources/js/purl.js"></script>
<script type="text/javascript" src="resources/js/lib/underscore.js"></script>
<script type="text/javascript" src="resources/js/lib/backbone.js"></script>
<script type="text/javascript" src="resources/js/lib/purl.js"></script>
<c:if test="${js != null && js != ''}">
<script type="text/javascript" src="${js}"></script>
</c:if>

View File

@ -52,7 +52,7 @@
<link rel="apple-touch-icon-precomposed" href="../bootstrap2/ico/apple-touch-icon-57-precomposed.png">
<!-- Load jQuery up here so that we can use in-page functions -->
<script type="text/javascript" src="resources/js/jquery.js"></script>
<script type="text/javascript" src="resources/js/lib/jquery.js"></script>
</head>
<body>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,451 @@
var ClientModel = Backbone.Model.extend({
idAttribute: "id",
initialize: function () {
// bind validation errors to dom elements
// this will display form elements in red if they are not valid
this.bind('error', function(model, errs) {
_.map(errs, function (val, elID) {
$('#' + elID).addClass('error');
});
});
},
// We can pass it default values.
defaults:{
id:null,
idTokenValiditySeconds: 600,
clientName:"",
clientSecret:"",
registeredRedirectUri:[],
authorizedGrantTypes:["authorization_code"],
scope:[],
authorities:[],
clientDescription:"",
logoUrl:"",
clientId:"",
allowRefresh:false,
accessTokenValiditySeconds: 3600,
refreshTokenValiditySeconds: 604800,
displayClientSecret: false,
generateClientSecret: false,
requireClientSecret: true,
allowIntrospection: false
},
urlRoot:"api/clients"
});
var ClientCollection = Backbone.Collection.extend({
initialize: function() {
//this.fetch();
},
model:ClientModel,
url:"api/clients",
getByClientId: function(clientId) {
var clients = this.where({clientId: clientId});
if (clients.length == 1) {
return clients[0];
} else {
return null;
}
}
});
var ClientView = Backbone.View.extend({
tagName: 'tr',
initialize:function () {
if (!this.template) {
this.template = _.template($('#tmpl-client').html());
}
if (!this.scopeTemplate) {
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
}
this.model.bind('change', this.render, this);
},
render:function (eventName) {
this.$el.html(this.template(this.model.toJSON()));
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scope'), systemScopes: app.systemScopeList}));
this.$('.dynamically-registered').tooltip({title: 'This client was dynamically registered'});
return this;
},
events:{
"click .btn-edit":"editClient",
"click .btn-delete":"deleteClient",
"click .btn-whitelist":"whiteListClient"
},
editClient:function () {
app.navigate('admin/client/' + this.model.id, {trigger: true});
},
whiteListClient:function() {
var whiteList = app.whiteListList.getByClientId(this.model.get('clientId'));
if (whiteList == null) {
// create a new one
app.navigate('admin/whitelist/new/' + this.model.id, {trigger: true});
} else {
// edit the existing one
app.navigate('admin/whitelist/' + whiteList.id, {trigger: true});
}
},
deleteClient:function () {
if (confirm("Are you sure sure you would like to delete this client?")) {
var self = this;
this.model.destroy({
success:function () {
self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
app.clientListView.togglePlaceholder();
});
});
}
});
app.clientListView.delegateEvents();
}
return false;
},
close:function () {
$(this.el).unbind();
$(this.el).empty();
}
});
var ClientListView = Backbone.View.extend({
tagName: 'span',
initialize:function () {
//this.model.bind("reset", this.render, this);
},
events:{
"click .new-client":"newClient",
"click .refresh-table":"refreshTable"
},
newClient:function () {
this.remove();
app.navigate('admin/client/new', {trigger: true});
},
render:function (eventName) {
// append and render table structure
$(this.el).html($('#tmpl-client-table').html());
_.each(this.model.models, function (client) {
$("#client-table",this.el).append(new ClientView({model:client}).render().el);
}, this);
this.togglePlaceholder();
return this;
},
togglePlaceholder:function() {
if (this.model.length > 0) {
$('#client-table', this.el).show();
$('#client-table-empty', this.el).hide();
} else {
$('#client-table', this.el).hide();
$('#client-table-empty', this.el).show();
}
},
refreshTable:function() {
var _self = this;
this.model.fetch({
success: function() {
_self.render();
}
});
}
});
var ClientFormView = Backbone.View.extend({
tagName:"span",
initialize:function () {
if (!this.template) {
this.template = _.template($('#tmpl-client-form').html());
}
this.registeredRedirectUriCollection = new Backbone.Collection();
this.scopeCollection = new Backbone.Collection();
},
events:{
"click .btn-save":"saveClient",
"click #allowRefresh" : "toggleRefreshTokenTimeout",
"click #disableAccessTokenTimeout" : function(){ $("#access-token-timeout-seconds", this.$el).prop('disabled',!$("#access-token-timeout-seconds", this.$el).prop('disabled')); },
"click #disableIDTokenTimeout" : function(){ $("#id-token-timeout-seconds", this.$el).prop('disabled',!$("#id-token-timeout-seconds", this.$el).prop('disabled')); },
"click #disableRefreshTokenTimeout" : function(){ $("#refresh-token-timeout-seconds", this.$el).prop('disabled',!$("#refresh-token-timeout-seconds", this.$el).prop('disabled')); },
"click .btn-cancel": function() { window.history.back(); return false; },
"change #requireClientSecret":"toggleRequireClientSecret",
"change #displayClientSecret":"toggleDisplayClientSecret",
"change #generateClientSecret":"toggleGenerateClientSecret",
"change #logoUrl input":"previewLogo"
},
toggleRefreshTokenTimeout:function () {
$("#refreshTokenValiditySeconds", this.$el).toggle();
},
previewLogo:function(event) {
if ($('#logoUrl input', this.el).val()) {
$('#logoPreview', this.el).empty();
$('#logoPreview', this.el).attr('src', $('#logoUrl input').val());
} else {
$('#logoBlock', this.el).hide();
}
},
/**
* Set up the form based on the current state of the requireClientSecret checkbox parameter
* @param event
*/
toggleRequireClientSecret:function(event) {
if ($('#requireClientSecret input', this.el).is(':checked')) {
// client secret is required, show all the bits
$('#clientSecretPanel', this.el).show();
// this function sets up the display portions
this.toggleGenerateClientSecret();
} else {
// no client secret, hide all the bits
$('#clientSecretPanel', this.el).hide();
}
},
/**
* Set up the form based on the "Generate" checkbox
* @param event
*/
toggleGenerateClientSecret:function(event) {
if ($('#generateClientSecret input', this.el).is(':checked')) {
// show the "generated" block, hide the "display" checkbox
$('#displayClientSecret', this.el).hide();
$('#clientSecret', this.el).hide();
$('#clientSecretGenerated', this.el).show();
$('#clientSecretHidden', this.el).hide();
} else {
// show the display checkbox, fall back to the "display" logic
$('#displayClientSecret', this.el).show();
this.toggleDisplayClientSecret(event);
}
},
/**
* Handle whether or not to display the client secret
* @param event
*/
toggleDisplayClientSecret:function(event) {
if ($('#displayClientSecret input').is(':checked')) {
// want to display it
$('#clientSecret', this.el).show();
$('#clientSecretHidden', this.el).hide();
$('#clientSecretGenerated', this.el).hide();
} else {
// want to hide it
$('#clientSecret', this.el).hide();
$('#clientSecretHidden', this.el).show();
$('#clientSecretGenerated', this.el).hide();
}
},
getFormTokenValue:function(value) {
if (value == "") return null;
else return value;
},
// maps from a form-friendly name to the real grant parameter name
authorizedGrantMap:{
"authorization_code": "authorization_code",
"password": "password",
"implicit": "implicit",
"client_credentials": "client_credentials",
"redelegate": "urn:ietf:params:oauth:grant_type:redelegate",
"refresh_token": "refresh_token"
},
saveClient:function (event) {
$('.control-group').removeClass('error');
// build the scope object
var scopes = this.scopeCollection.pluck("item");
// build the grant type object
var authorizedGrantTypes = [];
$.each(this.authorizedGrantMap, function(index,type) {
if ($('#authorizedGrantTypes-' + index).is(':checked')) {
authorizedGrantTypes.push(type);
}
});
var requireClientSecret = $('#requireClientSecret input').is(':checked');
var generateClientSecret = $('#generateClientSecret input').is(':checked');
var clientSecret = null;
if (requireClientSecret && !generateClientSecret) {
// if it's required but we're not generating it, send the value
clientSecret = $('#clientSecret input').val();
}
var accessTokenValiditySeconds = null;
if (!$('disableAccessTokenTimeout').is(':checked')) {
accessTokenValiditySeconds = this.getFormTokenValue($('#accessTokenValiditySeconds input[type=text]').val());
}
var idTokenValiditySeconds = null;
if (!$('disableIDTokenTimeout').is(':checked')) {
idTokenValiditySeconds = this.getFormTokenValue($('#idTokenValiditySeconds input[type=text]').val());
}
var refreshTokenValiditySeconds = null;
if ($('#allowRefresh').is(':checked')) {
if ($.inArray('refresh_token', authorizedGrantTypes) == -1) {
authorizedGrantTypes.push('refresh_token');
}
if ($.inArray('offline_access', scopes) == -1) {
scopes.push("offline_access");
}
if (!$('disableRefreshTokenTimeout').is(':checked')) {
refreshTokenValiditySeconds = this.getFormTokenValue($('#refreshTokenValiditySeconds input[type=text]').val());
}
}
var valid = this.model.set({
clientName:$('#clientName input').val(),
clientId:$('#clientId input').val(),
clientSecret: clientSecret,
generateClientSecret:generateClientSecret,
registeredRedirectUri: this.registeredRedirectUriCollection.pluck("item"),
clientDescription:$('#clientDescription textarea').val(),
logoUrl:$('#logoUrl input').val(),
authorizedGrantTypes: authorizedGrantTypes,
accessTokenValiditySeconds: accessTokenValiditySeconds,
refreshTokenValiditySeconds: refreshTokenValiditySeconds,
idTokenValiditySeconds: idTokenValiditySeconds,
allowRefresh: $('#allowRefresh').is(':checked'),
allowIntrospection: $('#allowIntrospection input').is(':checked'),
scope: scopes
});
// post-validate
// TODO: move these into the validation function somehow?
if (this.model.get("allowRefresh") == false) {
this.model.set("refreshTokenValiditySeconds",null);
}
if ($('#disableIDTokenTimeout').is(':checked')) {
this.model.set("idTokenValiditySeconds",null);
}
if ($('#disableAccessTokenTimeout').is(':checked')) {
this.model.set("accessTokenValiditySeconds",null);
}
if ($('#disableRefreshTokenTimeout').is(':checked')) {
this.model.set("refreshTokenValiditySeconds",null);
}
if (valid) {
var _self = this;
this.model.save({}, {
success:function () {
app.clientList.add(_self.model);
app.navigate('admin/clients', {trigger:true});
},
error:function (model,resp) {
console.error("Oops! The object didn't save correctly.",resp);
}
});
}
return false;
},
render:function (eventName) {
$(this.el).html(this.template(this.model.toJSON()));
var _self = this;
// build and bind registered redirect URI collection and view
_.each(this.model.get("registeredRedirectUri"), function (registeredRedirectUri) {
_self.registeredRedirectUriCollection.add(new URIModel({item:registeredRedirectUri}));
});
$("#registeredRedirectUri .controls",this.el).html(new ListWidgetView({type:'uri', placeholder: 'http://',
collection: this.registeredRedirectUriCollection}).render().el);
_self = this;
// build and bind scopes
_.each(this.model.get("scope"), function (scope) {
_self.scopeCollection.add(new Backbone.Model({item:scope}));
});
$("#scope .controls",this.el).html(new ListWidgetView({placeholder: 'new scope here'
, autocomplete: _.uniq(_.flatten(app.systemScopeList.pluck("value"))) // TODO: load from default scopes
, collection: this.scopeCollection}).render().el);
if (!this.model.get("allowRefresh")) {
$("#refreshTokenValiditySeconds", this.$el).hide();
}
if (this.model.get("accessTokenValiditySeconds") == null) {
$("#access-token-timeout-seconds", this.$el).prop('disabled',true);
}
if (this.model.get("refreshTokenValiditySeconds") == null) {
$("#refresh-token-timeout-seconds", this.$el).prop('disabled',true);
}
if (this.model.get("idTokenValiditySeconds") == null) {
$("#id-token-timeout-seconds", this.$el).prop('disabled',true);
}
this.toggleRequireClientSecret();
this.previewLogo();
return this;
}
});

View File

@ -0,0 +1,146 @@
var ApprovedSiteModel = Backbone.Model.extend({
idAttribute: 'id',
initialize: function() { },
urlRoot: 'api/approved'
});
var ApprovedSiteCollection = Backbone.Collection.extend({
initialize: function() { },
model: ApprovedSiteModel,
url: 'api/approved'
});
var ApprovedSiteListView = Backbone.View.extend({
tagName: 'span',
initialize:function() { },
events: {
"click .refresh-table":"refreshTable"
},
render:function (eventName) {
$(this.el).html($('#tmpl-grant-table').html());
_.each(this.model.models, function(approvedSite) {
// look up client
var client = app.clientList.getByClientId(approvedSite.get('clientId'));
if (client != null) {
if (approvedSite.get('whitelistedSite') != null) {
$('#grant-whitelist-table', this.el).append(new ApprovedSiteView({model: approvedSite, client: client}).render().el);
} else {
$('#grant-table', this.el).append(new ApprovedSiteView({model: approvedSite, client: client}).render().el);
}
}
}, this);
this.togglePlaceholder();
return this;
},
togglePlaceholder:function() {
// count the whitelisted and non-whitelisted entries
var wl = 0;
var gr = 0;
for (var i = 0; i < this.model.length; i++) {
if (this.model.at(i).get('whitelistedSite') != null) {
wl += 1;
} else {
gr += 1;
}
}
if (wl > 0) {
$('#grant-whitelist-table', this.el).show();
$('#grant-whitelist-table-empty', this.el).hide();
} else {
$('#grant-whitelist-table', this.el).hide();
$('#grant-whitelist-table-empty', this.el).show();
}
if (gr > 0) {
$('#grant-table', this.el).show();
$('#grant-table-empty', this.el).hide();
} else {
$('#grant-table', this.el).hide();
$('#grant-table-empty', this.el).show();
}
},
refreshTable:function() {
var _self = this;
this.model.fetch({
success: function() {
_self.render();
}
});
}
});
var ApprovedSiteView = Backbone.View.extend({
tagName: 'tr',
initialize: function() {
if (!this.template) {
this.template = _.template($('#tmpl-grant').html());
}
if (!this.scopeTemplate) {
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
}
},
render: function() {
var json = {grant: this.model.toJSON(), client: this.options.client.toJSON()};
this.$el.html(this.template(json));
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.options.client.get('scope'), systemScopes: app.systemScopeList}));
this.$('.dynamically-registered').tooltip({title: 'This client was dynamically registered'});
this.$('.whitelisted-site').tooltip({title: 'This site was whitelisted by an adminstrator'});
return this;
},
events: {
'click .btn-delete': 'deleteApprovedSite'
},
deleteApprovedSite:function() {
if (confirm("Are you sure you want to revoke access to this site?")) {
var self = this;
this.model.destroy({
success:function () {
self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
app.approvedSiteListView.togglePlaceholder();
});
});
}
});
app.approvedSiteListView.delegateEvents();
}
return false;
},
close:function() {
$(this.el).unbind();
$(this.el).empty();
}
});

View File

@ -0,0 +1,259 @@
var SystemScopeModel = Backbone.Model.extend({
idAttribute: 'id',
defaults:{
id:null,
description:null,
icon:null,
value:null,
defaultScope:false,
allowDynReg:false
},
urlRoot: 'api/scopes'
});
var SystemScopeCollection = Backbone.Collection.extend({
idAttribute: 'id',
model: SystemScopeModel,
url: 'api/scopes',
defaultScopes: function() {
filtered = this.filter(function(scope) {
return scope.get("defaultScope") === true;
});
return new SystemScopeCollection(filtered);
},
getByValue: function(value) {
var scopes = this.where({value: value});
if (scopes.length == 1) {
return scopes[0];
} else {
return null;
}
}
});
var SystemScopeView = Backbone.View.extend({
tagName: 'tr',
initialize:function () {
if (!this.template) {
this.template = _.template($('#tmpl-system-scope').html());
}
this.model.bind('change', this.render, this);
},
events: {
'click .btn-edit':'editScope',
'click .btn-delete':'deleteScope'
},
editScope:function() {
app.navigate('admin/scope/' + this.model.id, {trigger: true});
},
render:function (eventName) {
this.$el.html(this.template(this.model.toJSON()));
this.$('.dynamically-registered').tooltip({title: 'This client was dynamically registered'});
return this;
},
deleteScope:function () {
if (confirm("Are you sure sure you would like to delete this scope? Clients that have this scope will still be able to ask for it.")) {
var self = this;
this.model.destroy({
success:function () {
self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
app.systemScopeListView.togglePlaceholder();
});
});
}
});
app.systemScopeListView.delegateEvents();
}
return false;
},
close:function () {
$(this.el).unbind();
$(this.el).empty();
}
});
var SystemScopeListView = Backbone.View.extend({
tagName: 'span',
events:{
"click .new-scope":"newScope",
"click .refresh-table":"refreshTable"
},
newScope:function() {
this.remove();
app.navigate('admin/scope/new', {trigger: true});
},
refreshTable:function() {
var _self = this;
this.model.fetch({
success: function() {
_self.render();
}
});
},
togglePlaceholder:function() {
if (this.model.length > 0) {
$('#scope-table', this.el).show();
$('#scope-table-empty', this.el).hide();
} else {
$('#scope-table', this.el).hide();
$('#scope-table-empty', this.el).show();
}
},
render: function (eventName) {
// append and render the table structure
$(this.el).html($('#tmpl-system-scope-table').html());
_.each(this.model.models, function (scope) {
$("#scope-table", this.el).append(new SystemScopeView({model: scope}).render().el);
}, this);
this.togglePlaceholder();
return this;
}
});
var SystemScopeFormView = Backbone.View.extend({
tagName: 'span',
initialize:function() {
if (!this.template) {
this.template = _.template($('#tmpl-system-scope-form').html());
}
if (!this.iconTemplate) {
this.iconTemplate = _.template($('#tmpl-system-scope-icon').html());
}
// initialize our icon set into slices for the selector
if (!this.bootstrapIcons) {
this.bootstrapIcons = [];
var iconList = ['glass', 'music', 'search', 'envelope', 'heart', 'star',
'star-empty', 'user', 'film', 'th-large', 'th', 'th-list', 'ok',
'remove', 'zoom-in', 'zoom-out', 'off', 'signal', 'cog', 'trash',
'home', 'file', 'time', 'road', 'download-alt', 'download',
'upload', 'inbox', 'play-circle', 'repeat', 'refresh', 'list-alt',
'lock', 'flag', 'headphones', 'volume-off', 'volume-down',
'volume-up', 'qrcode', 'barcode', 'tag', 'tags', 'book',
'bookmark', 'print', 'camera', 'font', 'bold', 'italic',
'text-height', 'text-width', 'align-left', 'align-center',
'align-right', 'align-justify', 'list', 'indent-left',
'indent-right', 'facetime-video', 'picture', 'pencil',
'map-marker', 'tint', 'share', 'move', 'fast-backward', 'backward',
'pause', 'stop', 'forward', 'step-forward', 'eject',
'chevron-right', 'plus-sign', 'minus-sign', 'remove-sign',
'ok-sign', 'question-sign', 'info-sign', 'screenshot',
'remove-circle', 'ok-circle', 'ban-circle', 'arrow-left',
'arrow-right', 'arrow-down', 'share-alt', 'resize-full',
'resize-small', 'plus', 'asterisk', 'exclamation-sign', 'gift',
'leaf', 'fire', 'eye-close', 'plane', 'random', 'magnet',
'chevron-up', 'chevron-down', 'retweet', 'shopping-cart',
'folder-close', 'folder-open', 'resize-vertical',
'resize-horizontal', 'hdd', 'bell', 'thumbs-up', 'hand-right',
'hand-left', 'hand-down', 'circle-arrow-left', 'circle-arrow-up',
'circle-arrow-down', 'globe', 'tasks', 'briefcase' ];
var size = 3;
while (iconList.length > 0) {
this.bootstrapIcons.push(iconList.splice(0, size));
}
}
},
events:{
'click .btn-save':'saveScope',
'click .btn-cancel': function() {app.navigate('admin/scope', {trigger: true}); },
'click .btn-icon':'selectIcon'
},
saveScope:function(event) {
var value = $('#value input').val();
if (value == null || value.trim() == "") {
// error: can't have a blank scope
return false;
}
var valid = this.model.set({
value:value,
description:$('#description textarea').val(),
icon:$('#iconDisplay input').val(),
defaultScope:$('#defaultScope input').is(':checked'),
allowDynReg:$('#allowDynReg input').is(':checked')
});
if (valid) {
var _self = this;
this.model.save({}, {
success:function() {
app.systemScopeList.add(_self.model);
app.navigate('admin/scope', {trigger: true});
},
error:function(model,resp) {
console.error("The scope didn't save correctly.", resp);
}
});
}
return false;
},
selectIcon:function(event) {
var icon = event.target.value;
$('#iconDisplay input').val(icon);
$('#iconDisplay span').html(icon);
$('#iconDisplay i').removeClass();
$('#iconDisplay i').addClass('icon-' + icon);
$('#iconSelector').modal('hide');
return false;
},
render: function(eventName) {
this.$el.html(this.template(this.model.toJSON()));
_.each(this.bootstrapIcons, function (items) {
$(".modal-body", this.el).append(this.iconTemplate({items:items}));
}, this);
return this;
}
});

View File

@ -0,0 +1,223 @@
var WhiteListModel = Backbone.Model.extend({
idAttribute: "id",
initialize: function () { },
urlRoot: "api/whitelist"
});
var WhiteListCollection = Backbone.Collection.extend({
initialize: function() {
//this.fetch();
},
getByClientId: function(clientId) {
var clients = this.where({clientId: clientId});
if (clients.length == 1) {
return clients[0];
} else {
return null;
}
},
model: WhiteListModel,
url: "api/whitelist"
});
var WhiteListListView = Backbone.View.extend({
tagName: 'span',
initialize:function () {
//this.model.bind("reset", this.render, this);
},
events:{
"click .refresh-table":"refreshTable"
},
render:function (eventName) {
$(this.el).html($('#tmpl-whitelist-table').html());
_.each(this.model.models, function (whiteList) {
// look up client
var client = app.clientList.getByClientId(whiteList.get('clientId'));
// if there's no client ID, this is an error!
if (client != null) {
$('#whitelist-table', this.el).append(new WhiteListView({model: whiteList, client: client}).render().el);
}
}, this);
this.togglePlaceholder();
return this;
},
togglePlaceholder:function() {
if (this.model.length > 0) {
$('#whitelist-table', this.el).show();
$('#whitelist-table-empty', this.el).hide();
} else {
$('#whitelist-table', this.el).hide();
$('#whitelist-table-empty', this.el).show();
}
},
refreshTable:function() {
var _self = this;
this.model.fetch({
success: function() {
_self.render();
}
});
}
});
var WhiteListView = Backbone.View.extend({
tagName: 'tr',
initialize:function() {
if (!this.template) {
this.template = _.template($('#tmpl-whitelist').html());
}
if (!this.scopeTemplate) {
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
}
this.model.bind('change', this.render, this);
},
render:function(eventName) {
var json = {whiteList: this.model.toJSON(), client: this.options.client.toJSON()};
this.$el.html(this.template(json));
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('allowedScopes'), systemScopes: app.systemScopeList}));
this.$('.dynamically-registered').tooltip({title: 'This client was dynamically registered'});
return this;
},
events:{
'click .btn-edit': 'editWhitelist',
'click .btn-delete': 'deleteWhitelist'
},
editWhitelist:function() {
app.navigate('admin/whitelist/' + this.model.id, {trigger: true});
},
deleteWhitelist:function() {
if (confirm("Are you sure you want to delete this whitelist entry?")) {
var self = this;
this.model.destroy({
success:function () {
self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
// check the placeholder in case it's empty now
app.whiteListListView.togglePlaceholder();
});
});
}
});
app.whiteListListView.delegateEvents();
}
return false;
},
close:function() {
$(this.el).unbind();
$(this.el).empty();
}
});
var WhiteListFormView = Backbone.View.extend({
tagName: 'span',
initialize:function () {
if (!this.template) {
this.template = _.template($('#tmpl-whitelist-form').html());
}
this.scopeCollection = new Backbone.Collection();
},
events:{
'click .btn-save':'saveWhiteList',
'click .btn-cancel':'cancelWhiteList',
},
saveWhiteList:function (event) {
$('.control-group').removeClass('error');
// process allowed scopes
var allowedScopes = this.scopeCollection.pluck("item");
if (this.model.get('id') == null) {
this.model.set({clientId:$('#clientId input').val()});
}
var valid = this.model.set({
allowedScopes: allowedScopes
});
if (valid) {
var _self = this;
this.model.save({}, {
success:function () {
app.whiteListList.add(_self.model);
app.navigate('admin/whitelists', {trigger:true});
},
error:function (model,resp) {
console.error("Oops! The object didn't save correctly.",resp);
}
});
}
return false;
},
cancelWhiteList:function(event) {
app.navigate('admin/whitelists', {trigger:true});
},
render:function (eventName) {
var json = {whiteList: this.model.toJSON(), client: this.options.client.toJSON()};
this.$el.html(this.template(json));
var _self = this;
// build and bind scopes
_.each(this.model.get("allowedScopes"), function (scope) {
_self.scopeCollection.add(new Backbone.Model({item:scope}));
});
$("#scope .controls",this.el).html(new ListWidgetView({
placeholder: 'new scope here',
autocomplete: this.options.client.scope,
collection: this.scopeCollection}).render().el);
return this;
}
});

View File

@ -1,314 +1,3 @@
<!-- client -->
<script type="text/html" id="tmpl-client">
<td>
<% if (dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%=clientId%>
</td>
<td>
<%=clientName%>
<% if (clientDescription) { %>
<blockquote><small><%=clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
<!--expandable future information-->
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-warning btn-whitelist">Whitelist</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash icon-white"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-client-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-client"><i class="icon-plus icon-white"></i> New Client</button>
</div>
<div id="client-table-empty" class="alert alert-info">
There are no registered clients on this server.
</div>
<table id="client-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>ID</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-client"><i class="icon-plus icon-white"></i> New Client</button>
</div>
</script>
<script type="text/html" id="tmpl-client-form">
<h1><%=(id == null ? 'New' : 'Edit')%> Client</h1>
<form class="form-horizontal tabbable">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<ul class="nav nav-tabs">
<li class="active"><a data-target="#client-main-tab" data-toggle="tab" href="#">Main</a></li>
<li><a data-target="#client-access-tab" data-toggle="tab" href="#">Access</a></li>
<li><a data-target="#client-secret-tab" data-toggle="tab" href="#">Credentials</a></li>
<li><a data-target="#client-token-tab" data-toggle="tab" href="#">Tokens</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="client-main-tab">
<div class="control-group" id="clientName">
<label class="control-label">Client name</label>
<div class="controls">
<input value="<%=clientName%>" maxlength="100" type="text" class="" placeholder="Type something">
<p class="help-block">Human-readable application name</p>
</div>
</div>
<div class="control-group" id="clientId">
<label class="control-label">Client ID</label>
<div class="controls">
<input value="<%=clientId%>" maxlength="100" type="text" class="" placeholder="Type something">
<p class="help-block">Unique identifier. If you leave this blank it will be automatically generated.</p>
</div>
</div>
<div class="control-group" id="registeredRedirectUri">
<label class="control-label">Redirect URI(s)</label>
<div class="controls">
</div>
</div>
<div class="control-group" id="clientDescription">
<label class="control-label">Description</label>
<div class="controls">
<textarea class="input-xlarge" placeholder="Type a description" maxlength="200"
rows="3"><%=clientDescription%></textarea>
<p class="help-block">Human-readable text description</p>
</div>
</div>
<div class="control-group" id="logoUrl">
<label class="control-label">Logo URL</label>
<div class="controls">
<input placeholder="http://" value="<%=logoUrl%>" maxlength="100" type="text" class=""/>
<p class="help-block">URL to use for a logo image</p>
</div>
</div>
<div class="control-group" id="logoBlock">
<label class="control-label">Logo Preview</label>
<div class="controls">
<img src="http://placehold.it/275x200&text=Enter a logo URL" alt="logo" id="logoPreview" width="275px" class="thumbnail" />
</div>
</div>
</div>
<div class="tab-pane" id="client-access-tab">
<div class="control-group" id="scope">
<label class="control-label">Scope</label>
<div class="controls">
</div>
</div>
<div class="control-group" id="authorizedGrantTypes">
<label class="control-label">Authorized Grant Types</label>
<div class="controls">
<label class="checkbox">
<input id="authorizedGrantTypes-authorization_code" type="checkbox"
<%=($.inArray("authorization_code", authorizedGrantTypes) > -1 ? 'checked' : '')%>>
authorization code
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-client_credentials" type="checkbox"
<%=($.inArray("client_credentials", authorizedGrantTypes) > -1 ? 'checked' : '')%>> client
credentials
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-password" type="checkbox" <%=($.inArray("password",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> password
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-implicit" type="checkbox" <%=($.inArray("implicit",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> implicit
</label>
<!--
<label class="checkbox">
<input id="authorizedGrantTypes-refresh_token" type="checkbox" <%=($.inArray("refresh_token",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> refresh
</label>
-->
<label class="checkbox">
<input id="authorizedGrantTypes-redelegate" type="checkbox" <%=($.inArray("urn:ietf:params:oauth:grant_type:redelegate",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> redelegate
</label>
</div>
</div>
<div class="control-group" id="allowIntrospection">
<label class="control-label">Introspection</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(allowIntrospection == true ? 'checked' : '')%>> Allow calls to the Introspection Endpoint?
</label>
</div>
</div>
</div>
<div class="tab-pane" id="client-secret-tab">
<div class="control-group" id="requireClientSecret">
<label class="control-label">Client Secret</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(requireClientSecret == true ? 'checked' : '')%>> Require client secret?
</label>
</div>
</div>
<div id="clientSecretPanel">
<div class="control-group" id="generateClientSecret">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(generateClientSecret == true ? 'checked' : '')%>> Generate a new client secret?
</label>
<p class="help-block">New secret will be generated when you click 'Save'</p>
</div>
</div>
<div class="control-group" id="displayClientSecret">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(displayClientSecret == true ? 'checked' : '')%>> Display/edit client secret:
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<div id="clientSecret">
<input value="<%=clientSecret%>" maxlength="100" type="text" placeholder="Type a secret">
</div>
<div id="clientSecretGenerated">
<span class="uneditable-input span3">Generate on Save</span>
</div>
<div id="clientSecretHidden">
<span class="uneditable-input span3">* * * * * * * * * * * *</span>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="client-token-tab">
<div class="control-group" id="accessTokenValiditySeconds">
<label class="control-label">Access Token Timeout</label>
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableAccessTokenTimeout" <%=(accessTokenValiditySeconds == null ? 'checked' : '')%>/> Access tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(accessTokenValiditySeconds == null ? '' : accessTokenValiditySeconds)%>" id="access-token-timeout-seconds" size="16"><span class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
<div class="control-group" id="idTokenValiditySeconds">
<label class="control-label">ID Token Timeout</label>
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableIDTokenTimeout" <%=(idTokenValiditySeconds == null ? 'checked' : '')%>/> ID Tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(idTokenValiditySeconds == null ? '' : idTokenValiditySeconds)%>" id="id-token-timeout-seconds" size="16"><span
class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
<div class="control-group">
<label class="control-label">Refresh Tokens</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="allowRefresh" <%=(allowRefresh == true ? 'checked' : '')%>> Refresh tokens are issued for this client
</label>
</div>
</div>
<div class="control-group" id="refreshTokenValiditySeconds">
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableRefreshTokenTimeout" <%=(refreshTokenValiditySeconds == null ? 'checked' : '')%>/> Refresh tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(refreshTokenValiditySeconds == null ? '' : refreshTokenValiditySeconds)%>" id="refresh-token-timeout-seconds" size="16"><span class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
</div>
<div class="tab-pane" id="client-other-tab">
<div class="alert alert-block alert-info">
This page intentionally left blank.
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>
<!-- breadcrumbs -->
<script type="text/html" id="tmpl-breadcrumbs">
@ -338,199 +27,8 @@
</tbody>
</script>
<!-- whitelist -->
<script type="text/html" id="tmpl-whitelist">
<td>
<% if (client.dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%=whiteList.clientId%>
<% if (client.clientDescription) { %>
<blockquote><small><%=client.clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
</td>
<td>
<%=client.clientName%>
<!--expandable future information-->
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash icon-white"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-whitelist-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
<div id="whitelist-table-empty" class="alert alert-info">
There are no whitelisted sites. Use the <strong>whitelist</strong> button on the client management page to create one.
</div>
<table id="whitelist-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>ID</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
</script>
<script type="text/html" id="tmpl-whitelist-form">
<h1><%=(whiteList.id == null ? 'New' : 'Edit')%> Whitelisted Site</h1>
<form class="form-horizontal">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<div class="control-group" id="clientId">
<label class="control-label">Client</label>
<div class="controls">
<input type="hidden" name="clientId" value="<%= client.clientId %>" />
<%= client.clientName != null ? client.clientName : client.clientId %>
</div>
</div>
<div class="control-group" id="scope">
<label class="control-label">Allowed Scopes</label>
<div class="controls">
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>
<!-- approved sites (grants) -->
<script type="text/html" id="tmpl-grant-table">
<h2>Approved sites</h2>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
<h3>Sites you have manually approved</h3>
<div id="grant-table-empty" class="alert alert-info">
You have not approved any sites.
</div>
<table id="grant-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Application</th>
<th>Created</th>
<th>Last Accessed</th>
<th>Expires</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well">
<h3>Sites that have been whitelisted by an administrator</h3>
<p>If you revoke them here, they will automatically be re-approved on your next visit.</p>
<div id="grant-whitelist-table-empty" class="alert alert-info">
You have not accessed any whitelisted sites.
</div>
<table id="grant-whitelist-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Application</th>
<th>Created</th>
<th>Last Accessed</th>
<th>Expires</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
</script>
<script type="text/html" id="tmpl-grant">
<td>
<% if (client.dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%= client.clientName != null ? client.clientName : client.clientId %>
<% if (client.clientDescription) { %>
<blockquote><small><%=client.clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
</td>
<!-- TODO: make these dates collapsable/expandable -->
<td>
<%= grant.creationDate %>
</td>
<td>
<%= grant.accessDate %>
</td>
<td>
<%= grant.timeoutDate %>
</td>
<td>
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash"></i> Revoke</button>
</td>
</script>
<!-- blacklist -->
<!-- blacklist form -->
<script type="text/html" id="tmpl-blacklist-form">
<form class="form-horizontal">
@ -554,178 +52,3 @@
</script>
<!-- system scope -->
<script type="text/html" id = "tmpl-system-scope-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-scope"><i class="icon-plus icon-white"></i> New Scope</button>
</div>
<div id="scope-table-empty" class="alert alert-info">
There are no system scopes defined. Clients may still have custom scopes.
</div>
<table id="scope-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Scope</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-scope"><i class="icon-plus icon-white"></i> New Scope</button>
</div>
</script>
<script type="text/html" id="tmpl-system-scope">
<td>
<% if (icon) { %>
<i class="icon-<%= icon %>"></i>
<% } %>
</td>
<td>
<%= value %>
<blockquote><small><%= description %></small></blockquote>
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-system-scope-form">
<h1><%= id == null ? 'New' : 'Edit'%> Scope</h1>
<form class="form-horizontal">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<div class="control-group" id="value">
<label class="control-label">Scope value</label>
<div class="controls">
<input value="<%=value != null ? value : ''%>" type="text" class="" placeholder="scope">
<p class="help-block">Single string with no spaces</p>
</div>
</div>
<div class="control-group" id="description">
<label class="control-label">Description</label>
<div class="controls">
<textarea class="input-xlarge" placeholder="Type a description" maxlength="200" rows="3"><%=description != null ? description : ''%></textarea>
<p class="help-block">Human-readable text description</p>
</div>
</div>
<div class="control-group" id="icon">
<label class="control-label">Icon</label>
<div class="controls">
<span id="iconDisplay">
<i class="icon-<%=icon%>"></i> <span class="uneditable-input"><%=icon%></span>
<input type="hidden" value="<%=icon%>">
</span>
<a href="#iconSelector" role="button" class="btn btn-info" data-toggle="modal"><i class="icon-white icon-picture"></i> Select an icon</a>
<div id="iconSelector" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="iconSelectorLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 id="iconSelectorLabel">Select an Icon</h3>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
</div>
</div>
<div class="control-group" id="defaultScope">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=defaultScope ? 'checked' : '' %>> default scope
</label>
<p class="help-block">Newly-created clients get this scope by default?</p>
</div>
</div>
<div class="control-group" id="allowDynReg">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=allowDynReg ? 'checked' : '' %>> allow dynamic registration
</label>
<p class="help-block">Allow dynamically registered clients to request this scope?</p>
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>
<script type="text/html" id="tmpl-system-scope-icon">
<div class="row-fluid">
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[0]) { %>
<button class="btn btn-block btn-icon" value="<%=items[0]%>"><i class="icon-<%=items[0]%>"></i> <%=items[0]%>
<% } %>
</div>
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[1]) { %>
<button class="btn btn-block btn-icon" value="<%=items[1]%>"><i class="icon-<%=items[1]%>"></i> <%=items[1]%>
<% } %>
</div>
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[2]) { %>
<button class="btn btn-block btn-icon" value="<%=items[2]%>"><i class="icon-<%=items[2]%>"></i> <%=items[2]%>
<% } %>
</div>
</div>
</script>
<script type="text/html" id="tmpl-scope-list">
<%
_.each(scopes, function(s) {
%>
<span class="badge badge-info">
<%
var ss = systemScopes.getByValue(s);
if (ss && ss.get('icon')) {
%>
<i class="icon-<%=ss.get('icon')%> icon-white"></i>
<%
}
%>
<%=s%>
</span>
<%
});
%>
</script>

View File

@ -0,0 +1,310 @@
<!-- client -->
<script type="text/html" id="tmpl-client">
<td>
<% if (dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%=clientId%>
</td>
<td>
<%=clientName%>
<% if (clientDescription) { %>
<blockquote><small><%=clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
<!--expandable future information-->
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-warning btn-whitelist">Whitelist</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash icon-white"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-client-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-client"><i class="icon-plus icon-white"></i> New Client</button>
</div>
<div id="client-table-empty" class="alert alert-info">
There are no registered clients on this server.
</div>
<table id="client-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>ID</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-client"><i class="icon-plus icon-white"></i> New Client</button>
</div>
</script>
<script type="text/html" id="tmpl-client-form">
<h1><%=(id == null ? 'New' : 'Edit')%> Client</h1>
<form class="form-horizontal tabbable">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<ul class="nav nav-tabs">
<li class="active"><a data-target="#client-main-tab" data-toggle="tab" href="#">Main</a></li>
<li><a data-target="#client-access-tab" data-toggle="tab" href="#">Access</a></li>
<li><a data-target="#client-secret-tab" data-toggle="tab" href="#">Credentials</a></li>
<li><a data-target="#client-token-tab" data-toggle="tab" href="#">Tokens</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="client-main-tab">
<div class="control-group" id="clientName">
<label class="control-label">Client name</label>
<div class="controls">
<input value="<%=clientName%>" maxlength="100" type="text" class="" placeholder="Type something">
<p class="help-block">Human-readable application name</p>
</div>
</div>
<div class="control-group" id="clientId">
<label class="control-label">Client ID</label>
<div class="controls">
<input value="<%=clientId%>" maxlength="100" type="text" class="" placeholder="Type something">
<p class="help-block">Unique identifier. If you leave this blank it will be automatically generated.</p>
</div>
</div>
<div class="control-group" id="registeredRedirectUri">
<label class="control-label">Redirect URI(s)</label>
<div class="controls">
</div>
</div>
<div class="control-group" id="clientDescription">
<label class="control-label">Description</label>
<div class="controls">
<textarea class="input-xlarge" placeholder="Type a description" maxlength="200"
rows="3"><%=clientDescription%></textarea>
<p class="help-block">Human-readable text description</p>
</div>
</div>
<div class="control-group" id="logoUrl">
<label class="control-label">Logo URL</label>
<div class="controls">
<input placeholder="http://" value="<%=logoUrl%>" maxlength="100" type="text" class=""/>
<p class="help-block">URL to use for a logo image</p>
</div>
</div>
<div class="control-group" id="logoBlock">
<label class="control-label">Logo Preview</label>
<div class="controls">
<img src="http://placehold.it/275x200&text=Enter a logo URL" alt="logo" id="logoPreview" width="275px" class="thumbnail" />
</div>
</div>
</div>
<div class="tab-pane" id="client-access-tab">
<div class="control-group" id="scope">
<label class="control-label">Scope</label>
<div class="controls">
</div>
</div>
<div class="control-group" id="authorizedGrantTypes">
<label class="control-label">Authorized Grant Types</label>
<div class="controls">
<label class="checkbox">
<input id="authorizedGrantTypes-authorization_code" type="checkbox"
<%=($.inArray("authorization_code", authorizedGrantTypes) > -1 ? 'checked' : '')%>>
authorization code
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-client_credentials" type="checkbox"
<%=($.inArray("client_credentials", authorizedGrantTypes) > -1 ? 'checked' : '')%>> client
credentials
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-password" type="checkbox" <%=($.inArray("password",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> password
</label>
<label class="checkbox">
<input id="authorizedGrantTypes-implicit" type="checkbox" <%=($.inArray("implicit",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> implicit
</label>
<!--
<label class="checkbox">
<input id="authorizedGrantTypes-refresh_token" type="checkbox" <%=($.inArray("refresh_token",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> refresh
</label>
-->
<label class="checkbox">
<input id="authorizedGrantTypes-redelegate" type="checkbox" <%=($.inArray("urn:ietf:params:oauth:grant_type:redelegate",
authorizedGrantTypes) > -1 ? 'checked' : '')%>> redelegate
</label>
</div>
</div>
<div class="control-group" id="allowIntrospection">
<label class="control-label">Introspection</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(allowIntrospection == true ? 'checked' : '')%>> Allow calls to the Introspection Endpoint?
</label>
</div>
</div>
</div>
<div class="tab-pane" id="client-secret-tab">
<div class="control-group" id="requireClientSecret">
<label class="control-label">Client Secret</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(requireClientSecret == true ? 'checked' : '')%>> Require client secret?
</label>
</div>
</div>
<div id="clientSecretPanel">
<div class="control-group" id="generateClientSecret">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(generateClientSecret == true ? 'checked' : '')%>> Generate a new client secret?
</label>
<p class="help-block">New secret will be generated when you click 'Save'</p>
</div>
</div>
<div class="control-group" id="displayClientSecret">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=(displayClientSecret == true ? 'checked' : '')%>> Display/edit client secret:
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<div id="clientSecret">
<input value="<%=clientSecret%>" maxlength="100" type="text" placeholder="Type a secret">
</div>
<div id="clientSecretGenerated">
<span class="uneditable-input span3">Generate on Save</span>
</div>
<div id="clientSecretHidden">
<span class="uneditable-input span3">* * * * * * * * * * * *</span>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="client-token-tab">
<div class="control-group" id="accessTokenValiditySeconds">
<label class="control-label">Access Token Timeout</label>
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableAccessTokenTimeout" <%=(accessTokenValiditySeconds == null ? 'checked' : '')%>/> Access tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(accessTokenValiditySeconds == null ? '' : accessTokenValiditySeconds)%>" id="access-token-timeout-seconds" size="16"><span class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
<div class="control-group" id="idTokenValiditySeconds">
<label class="control-label">ID Token Timeout</label>
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableIDTokenTimeout" <%=(idTokenValiditySeconds == null ? 'checked' : '')%>/> ID Tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(idTokenValiditySeconds == null ? '' : idTokenValiditySeconds)%>" id="id-token-timeout-seconds" size="16"><span
class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
<div class="control-group">
<label class="control-label">Refresh Tokens</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="allowRefresh" <%=(allowRefresh == true ? 'checked' : '')%>> Refresh tokens are issued for this client
</label>
</div>
</div>
<div class="control-group" id="refreshTokenValiditySeconds">
<div class="controls">
<div>
<label class="checkbox">
<input type="checkbox" id="disableRefreshTokenTimeout" <%=(refreshTokenValiditySeconds == null ? 'checked' : '')%>/> Refresh tokens do not time out
</label>
</div>
<div class="input-append">
<input type="text" class="" value="<%=(refreshTokenValiditySeconds == null ? '' : refreshTokenValiditySeconds)%>" id="refresh-token-timeout-seconds" size="16"><span class="add-on">seconds</span>
</div>
<p class="help-block">Enter this time in seconds.</p>
</div>
</div>
</div>
<div class="tab-pane" id="client-other-tab">
<div class="alert alert-block alert-info">
This page intentionally left blank.
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>

View File

@ -0,0 +1,99 @@
<!-- approved sites (grants) -->
<script type="text/html" id="tmpl-grant-table">
<h2>Approved sites</h2>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
<h3>Sites you have manually approved</h3>
<div id="grant-table-empty" class="alert alert-info">
You have not approved any sites.
</div>
<table id="grant-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Application</th>
<th>Created</th>
<th>Last Accessed</th>
<th>Expires</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well">
<h3>Sites that have been whitelisted by an administrator</h3>
<p>If you revoke them here, they will automatically be re-approved on your next visit.</p>
<div id="grant-whitelist-table-empty" class="alert alert-info">
You have not accessed any whitelisted sites.
</div>
<table id="grant-whitelist-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Application</th>
<th>Created</th>
<th>Last Accessed</th>
<th>Expires</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
</script>
<script type="text/html" id="tmpl-grant">
<td>
<% if (client.dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%= client.clientName != null ? client.clientName : client.clientId %>
<% if (client.clientDescription) { %>
<blockquote><small><%=client.clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
</td>
<!-- TODO: make these dates collapsable/expandable -->
<td>
<%= grant.creationDate %>
</td>
<td>
<%= grant.accessDate %>
</td>
<td>
<%= grant.timeoutDate %>
</td>
<td>
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash"></i> Revoke</button>
</td>
</script>

View File

@ -0,0 +1,175 @@
<!-- system scope -->
<script type="text/html" id = "tmpl-system-scope-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-scope"><i class="icon-plus icon-white"></i> New Scope</button>
</div>
<div id="scope-table-empty" class="alert alert-info">
There are no system scopes defined. Clients may still have custom scopes.
</div>
<table id="scope-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>Scope</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button> &nbsp;
<button class="btn btn-small btn-primary new-scope"><i class="icon-plus icon-white"></i> New Scope</button>
</div>
</script>
<script type="text/html" id="tmpl-system-scope">
<td>
<% if (icon) { %>
<i class="icon-<%= icon %>"></i>
<% } %>
</td>
<td>
<%= value %>
<blockquote><small><%= description %></small></blockquote>
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-system-scope-form">
<h1><%= id == null ? 'New' : 'Edit'%> Scope</h1>
<form class="form-horizontal">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<div class="control-group" id="value">
<label class="control-label">Scope value</label>
<div class="controls">
<input value="<%=value != null ? value : ''%>" type="text" class="" placeholder="scope">
<p class="help-block">Single string with no spaces</p>
</div>
</div>
<div class="control-group" id="description">
<label class="control-label">Description</label>
<div class="controls">
<textarea class="input-xlarge" placeholder="Type a description" maxlength="200" rows="3"><%=description != null ? description : ''%></textarea>
<p class="help-block">Human-readable text description</p>
</div>
</div>
<div class="control-group" id="icon">
<label class="control-label">Icon</label>
<div class="controls">
<span id="iconDisplay">
<i class="icon-<%=icon%>"></i> <span class="uneditable-input"><%=icon%></span>
<input type="hidden" value="<%=icon%>">
</span>
<a href="#iconSelector" role="button" class="btn btn-info" data-toggle="modal"><i class="icon-white icon-picture"></i> Select an icon</a>
<div id="iconSelector" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="iconSelectorLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 id="iconSelectorLabel">Select an Icon</h3>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
</div>
</div>
<div class="control-group" id="defaultScope">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=defaultScope ? 'checked' : '' %>> default scope
</label>
<p class="help-block">Newly-created clients get this scope by default?</p>
</div>
</div>
<div class="control-group" id="allowDynReg">
<div class="controls">
<label class="checkbox">
<input type="checkbox" <%=allowDynReg ? 'checked' : '' %>> allow dynamic registration
</label>
<p class="help-block">Allow dynamically registered clients to request this scope?</p>
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>
<script type="text/html" id="tmpl-system-scope-icon">
<div class="row-fluid">
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[0]) { %>
<button class="btn btn-block btn-icon" value="<%=items[0]%>"><i class="icon-<%=items[0]%>"></i> <%=items[0]%>
<% } %>
</div>
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[1]) { %>
<button class="btn btn-block btn-icon" value="<%=items[1]%>"><i class="icon-<%=items[1]%>"></i> <%=items[1]%>
<% } %>
</div>
<div class="span4" style="margin-top: 5px; margin-bottom: 5px;">
<% if (items[2]) { %>
<button class="btn btn-block btn-icon" value="<%=items[2]%>"><i class="icon-<%=items[2]%>"></i> <%=items[2]%>
<% } %>
</div>
</div>
</script>
<script type="text/html" id="tmpl-scope-list">
<%
_.each(scopes, function(s) {
%>
<span class="badge badge-info">
<%
var ss = systemScopes.getByValue(s);
if (ss && ss.get('icon')) {
%>
<i class="icon-<%=ss.get('icon')%> icon-white"></i>
<%
}
%>
<%=s%>
</span>
<%
});
%>
</script>

View File

@ -0,0 +1,92 @@
<!-- whitelist -->
<script type="text/html" id="tmpl-whitelist">
<td>
<% if (client.dynamicallyRegistered) { %>
<span class="dynamically-registered"><i class="icon-globe"></i></span>
<% } %>
</td>
<td>
<%=whiteList.clientId%>
<% if (client.clientDescription) { %>
<blockquote><small><%=client.clientDescription%></small></blockquote>
<% } %>
<div class="scope-list"></div>
</td>
<td>
<%=client.clientName%>
<!--expandable future information-->
</td>
<td>
<button class="btn btn-edit"><i class="icon-edit"></i> Edit</button> &nbsp;
<button class="btn btn-danger btn-delete pull-right"><i class="icon-trash icon-white"></i> Delete</button>
</td>
</script>
<script type="text/html" id="tmpl-whitelist-table">
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
<div id="whitelist-table-empty" class="alert alert-info">
There are no whitelisted sites. Use the <strong>whitelist</strong> button on the client management page to create one.
</div>
<table id="whitelist-table" class="table table-hover table-striped">
<thead>
<tr>
<th></th>
<th>ID</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="well well-small">
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> Refresh</button>
</div>
</script>
<script type="text/html" id="tmpl-whitelist-form">
<h1><%=(whiteList.id == null ? 'New' : 'Edit')%> Whitelisted Site</h1>
<form class="form-horizontal">
<fieldset>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
<div class="control-group" id="clientId">
<label class="control-label">Client</label>
<div class="controls">
<input type="hidden" name="clientId" value="<%= client.clientId %>" />
<%= client.clientName != null ? client.clientName : client.clientId %>
</div>
</div>
<div class="control-group" id="scope">
<label class="control-label">Allowed Scopes</label>
<div class="controls">
</div>
</div>
<div class="well well-small">
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> Save</button> &nbsp;
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> Cancel</button>
</div>
</fieldset>
</form>
</script>