Skip to content

Commit

Permalink
added password protection
Browse files Browse the repository at this point in the history
closes #4993
- brings password protection to the frontend of blogs
- modified gh-count-chars to have a max value
  • Loading branch information
acburdine committed Apr 4, 2015
1 parent 242388f commit f1da669
Show file tree
Hide file tree
Showing 21 changed files with 354 additions and 9 deletions.
4 changes: 4 additions & 0 deletions core/client/app/controllers/feature.js
Expand Up @@ -28,6 +28,10 @@ var FeatureController = Ember.Controller.extend(Ember.PromiseProxyMixin, {

codeInjectionUI: Ember.computed('config.codeInjectionUI', 'labs.codeInjectionUI', function () {
return this.get('config.codeInjectionUI') || this.get('labs.codeInjectionUI');
}),

passProtectUI: Ember.computed('config.passProtectUI', 'labs.passProtectUI', function () {
return this.get('config.passProtectUI') || this.get('labs.passProtectUI');
})
});

Expand Down
3 changes: 3 additions & 0 deletions core/client/app/controllers/settings.js
Expand Up @@ -22,6 +22,9 @@ var SettingsController = Ember.Controller.extend({
}),
showAbout: Ember.computed('session.user.name', function () {
return this.get('session.user.isAuthor') ? false : true;
}),
showPassProtection: Ember.computed('session.user.name', 'controllers.feature.passProtectUI', function () {
return this.get('session.user.isAuthor') || this.get('session.user.isEditor') || !this.get('controllers.feature.passProtectUI') ? false : true;
})
});

Expand Down
10 changes: 10 additions & 0 deletions core/client/app/controllers/settings/labs.js
Expand Up @@ -35,6 +35,16 @@ var LabsController = Ember.Controller.extend(Ember.Evented, {
return this.get('controllers.feature.codeInjectionUI') || false;
}),

usePassProtectUI: Ember.computed('controllers.feature.passProtectUI', function (key, value) {
// setter
if (arguments.length > 1) {
this.saveLabs('passProtectUI', value);
}

// getter
return this.get('controllers.feature.passProtectUI');
}),

actions: {
onUpload: function (file) {
var self = this,
Expand Down
22 changes: 22 additions & 0 deletions core/client/app/controllers/settings/pass-protect.js
@@ -0,0 +1,22 @@
import Ember from 'ember';

var SettingsPassProtectController = Ember.Controller.extend({

actions: {
save: function () {
var self = this;

return this.get('model').save().then(function (model) {
self.notifications.closePassive();
self.notifications.showSuccess('Settings successfully saved.');

return model;
}).catch(function (errors) {
self.notifications.closePassive();
self.notifications.showErrors(errors);
});
}
}
});

export default SettingsPassProtectController;
13 changes: 10 additions & 3 deletions core/client/app/helpers/gh-count-characters.js
@@ -1,6 +1,7 @@
import Ember from 'ember';
var countCharacters = Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
var el = document.createElement('span'),
max,
length,
content;

Expand All @@ -11,15 +12,21 @@ var countCharacters = Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams
content = arr[0] || '';
length = content.length;

if (arr.length === 2) { // allows for input of maximum characters
max = arr[1];
} else {
max = 200;
}

el.className = 'word-count';

if (length > 180) {
if (length > (max - (max / 10))) {
el.style.color = '#E25440';
} else {
el.style.color = '#9E9D95';
el.style.color = '#9E9D95'; // when length is less than 10% of the maximum allowed characters
}

el.innerHTML = 200 - length;
el.innerHTML = max - length;

return Ember.String.htmlSafe(el.outerHTML);
});
Expand Down
4 changes: 3 additions & 1 deletion core/client/app/models/setting.js
Expand Up @@ -19,7 +19,9 @@ var Setting = DS.Model.extend(NProgressSaveMixin, ValidationEngine, {
ghost_head: DS.attr('string'),
ghost_foot: DS.attr('string'),
labs: DS.attr('string'),
navigation: DS.attr('string')
navigation: DS.attr('string'),
password: DS.attr('string'),
message: DS.attr('string')
});

export default Setting;
1 change: 1 addition & 0 deletions core/client/app/router.js
Expand Up @@ -43,6 +43,7 @@ Router.map(function () {
this.route('labs');
this.route('code-injection');
this.route('navigation');
this.route('pass-protect');
});

// Redirect debug to settings labs
Expand Down
44 changes: 44 additions & 0 deletions core/client/app/routes/settings/pass-protect.js
@@ -0,0 +1,44 @@
import AuthenticatedRoute from 'ghost/routes/authenticated';
import loadingIndicator from 'ghost/mixins/loading-indicator';
import CurrentUserSettings from 'ghost/mixins/current-user-settings';
import styleBody from 'ghost/mixins/style-body';

var SettingsPassProtectRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, {
classNames: ['settings-view-pass'],

beforeModel: function () {
var feature = this.controllerFor('feature'),
self = this;

if (!feature) {
this.generateController('feature');
feature = this.controllerFor('feature');
}

return this.currentUser()
.then(this.transitionAuthor())
.then(this.transitionEditor())
.then(function () {
return feature.then(function () {
if (!feature.get('passProtectUI')) {
return self.transitionTo('settings.general');
}
});
});
},

model: function () {
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
return records.get('firstObject');
});
},

actions: {
save: function () {
this.get('controller').send('save');
}
}

});

export default SettingsPassProtectRoute;
4 changes: 4 additions & 0 deletions core/client/app/templates/settings.hbs
Expand Up @@ -27,6 +27,10 @@
{{gh-activating-list-item route="settings.code-injection" title="Code Injection" classNames="settings-nav-code icon-code"}}
{{/if}}

{{#if showPassProtection}}
{{gh-activating-list-item route="settings.pass-protect" title="Password Protection" classNames="settings-nav-pass icon-lock"}}
{{/if}}

{{#if showLabs}}
{{gh-activating-list-item route="settings.labs" title="Labs" classNames="settings-nav-labs icon-atom"}}
{{/if}}
Expand Down
17 changes: 16 additions & 1 deletion core/client/app/templates/settings/labs.hbs
Expand Up @@ -50,7 +50,7 @@
{{#unless codeUIFlag}}
<div class="form-group for-checkbox">
<label for="labs-codeInjectionUI">Code Injection</label>
<label class="check box" for="labs-codeInjectionUI">
<label class="checkbox" for="labs-codeInjectionUI">
{{input id="labs-codeInjectionUI" name="labs[codeInjectionUI]" type="checkbox"
checked=useCodeInjectionUI}}
<span class="input-toggle-component"></span>
Expand All @@ -62,4 +62,19 @@
</fieldset>
</form>

<form>
<fieldset>
<div class="form-group for-checkbox">
<label for="labs-passProtectUI">Password Protection</label>
<label class="checkbox" for="labs-passProtectUI">
{{input id="labs-passProtectUI" name="labs[passProtectUI]" type="checkbox"
checked=usePassProtectUI}}
<span class="input-toggle-component"></span>
<p>Enable the password protection interface</p>
</label>
<p>A settings screen which enables you to add password protection to the front of your blog (work in progress)</p>
</div>
</fieldset>
</form>

</section>
35 changes: 35 additions & 0 deletions core/client/app/templates/settings/pass-protect.hbs
@@ -0,0 +1,35 @@
<header class="settings-view-header">
{{#link-to "settings" class="btn btn-default btn-back"}}Back{{/link-to}}
<h2 class="page-title">Password protect your blog</h2>
<section class="page-actions">
<button type="button" class="btn btn-blue" {{action "save"}}>Save</button>
</section>
</header>

<section class="content settings-pass">
<form id="settings-pass" novalidate="novalidate">
<fieldset>
<div class="form-group">
<p>
Ghost allows you to set a password for the front-end of your blog. Users that go to your site will be asked to enter a password, and upon correct password entry, they will be able to view your blog.
</p>
</div>

<div class="form-group">
<label for="protected-password">Password</label>
{{input id="protected-password" name="passProtect[protectionPassword]" type="text" value=model.password}}
<p>The password visitors will enter to see your blog</p>
</div>

<div class="form-group">
<label for="protected-message">Message</label>
{{textarea id="protected-message" name="passProtect[protectionMessage]" value=model.message}}
<p>
A message to display to people who visit your blog
{{gh-count-characters protectionMessage 2000}}
</p>
</div>

</fieldset>
</form>
</section>
5 changes: 5 additions & 0 deletions core/client/app/views/settings/pass-protect.js
@@ -0,0 +1,5 @@
import BaseView from 'ghost/views/settings/content-base';

var SettingsGeneralView = BaseView.extend();

export default SettingsGeneralView;
2 changes: 1 addition & 1 deletion core/server/config/url.js
Expand Up @@ -89,7 +89,7 @@ function urlPathForPost(post, permalinks) {
// Usage:
// urlFor('home', true) -> http://my-ghost-blog.com/
// E.g. /blog/ subdir
// urlFor({relativeUrl: '/my-static-page/') -> /blog/my-static-page/
// urlFor({relativeUrl: '/my-static-page/'}) -> /blog/my-static-page/
// E.g. if post object represents welcome post, and slugs are set to standard
// urlFor('post', {...}) -> /welcome-to-ghost/
// E.g. if post object represents welcome post, and slugs are set to date
Expand Down
19 changes: 19 additions & 0 deletions core/server/controllers/frontend.js
Expand Up @@ -17,6 +17,7 @@ var moment = require('moment'),
cheerio = require('cheerio'),
downsize = require('downsize'),
routeMatch = require('path-match')(),
path = require('path'),

frontendControllers,
staticPostPermalink,
Expand Down Expand Up @@ -588,6 +589,24 @@ frontendControllers = {
});
});
}).catch(handleError(next));
},
private: function (req, res, next) {
var defaultPage = path.resolve(config.paths.adminViews, 'password.hbs');
getActiveThemePaths().then(function (paths) {
api.settings.read({context: {internal: true}, key: 'message'}).then(function (response) {
var message = response.settings[0];
if(paths.hasOwnProperty('password.hbs'))
res.render('password', {
message: message.value,
forward: req.query.r
});
else
res.render(defaultPage, {
message: message.value,
forward: req.query.r
});
});
});
}
};

Expand Down
6 changes: 6 additions & 0 deletions core/server/data/default-settings.json
Expand Up @@ -73,6 +73,12 @@
},
"navigation": {
"defaultValue": "[{\"label\":\"Home\", \"url\":\"/\"}]"
},
"password": {
"defaultValue": ""
},
"message": {
"defaultValue": ""
}
},
"theme": {
Expand Down
6 changes: 5 additions & 1 deletion core/server/middleware/index.js
Expand Up @@ -260,6 +260,10 @@ setupMiddleware = function (blogAppInstance, adminApp) {
// Theme only config
blogApp.use(middleware.staticTheme());

// Check if password protected blog
blogApp.use(middleware.checkIsProtected);
blogApp.use(middleware.checkPasswordProtection);

// Serve robots.txt if not found in theme
blogApp.use(serveSharedFile('robots.txt', 'text/plain', utils.ONE_HOUR_S));

Expand Down Expand Up @@ -301,7 +305,7 @@ setupMiddleware = function (blogAppInstance, adminApp) {
blogApp.use('/ghost', adminApp);

// Set up Frontend routes
blogApp.use(routes.frontend());
blogApp.use(routes.frontend(middleware));

// ### Error handling
// 404 Handler
Expand Down

0 comments on commit f1da669

Please sign in to comment.