whats wrong?

This commit is contained in:
Martin Donnelly 2016-04-06 16:53:06 +01:00
commit e06e53e5bd
142 changed files with 4082 additions and 0 deletions

4
.bowerrc Normal file
View File

@ -0,0 +1,4 @@
{
"directory": "bower_components",
"analytics": false
}

26
.editorconfig Normal file
View File

@ -0,0 +1,26 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.{js,json,hbs,html,css}]
indent_style = space
indent_size = 2
[*.hbs]
insert_final_newline = false
[*.{diff,md}]
indent_size = 2
trim_trailing_whitespace = false

9
.ember-cli Normal file
View File

@ -0,0 +1,9 @@
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
}

192
.gitignore vendored Normal file
View File

@ -0,0 +1,192 @@
### Archives template
# It's better to unpack these files and commit the raw source because
# git has its own built in compression methods.
*.7z
*.jar
*.rar
*.zip
*.gz
*.bzip
*.bz2
*.xz
*.lzma
*.cab
#packing-only formats
*.iso
*.tar
#package management formats
*.dmg
*.xpi
*.gem
*.egg
*.deb
*.rpm
*.msi
*.msm
*.msp
### Windows template
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Xcode template
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
### OSX template
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Node template
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
node_modules
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
# dependencies
/node_modules
/bower_components
# misc
/.sass-cache
/connect.lock
/coverage/*
/libpeerconnection.log
npm-debug.log
testem.log
/.cache
/.gradle

46
.jscsrc Normal file
View File

@ -0,0 +1,46 @@
{
"disallowKeywords": ["with"],
"disallowKeywordsOnNewLine": ["else"],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleVarDecl": "exceptUndefined",
"disallowNewlineBeforeBlockStatements": true,
"disallowQuotedKeysInObjects": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowSpacesInFunction": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideParentheses": true,
"disallowTrailingWhitespace": true,
"maximumLineLength": 120,
"requireCamelCaseOrUpperCaseIdentifiers": false,
"requireCapitalizedComments": true,
"requireCapitalizedConstructors": true,
"requireCurlyBraces": true,
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"case",
"return",
"try",
"catch",
"typeof"
],
"requireSpaceAfterLineComment": true,
"requireSpaceAfterBinaryOperators": true,
"requireSpaceBeforeBinaryOperators": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpaceBeforeObjectValues": true,
"requireSpacesInFunction": {
"beforeOpeningCurlyBrace": true
},
"requireTrailingComma": false,
"requireEarlyReturn": true,
"validateIndentation": 2,
"validateLineBreaks": "LF",
"validateQuoteMarks": "'"
}

33
.jshintrc Normal file
View File

@ -0,0 +1,33 @@
{
"predef": [
"server",
"document",
"window",
"-Promise"
],
"browser": true,
"boss": true,
"curly": true,
"debug": false,
"devel": true,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"esnext": true,
"unused": true
}

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
---
language: node_js
node_js:
- "0.12"
sudo: false
cache:
directories:
- node_modules
before_install:
- export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
- "npm config set spin false"
- "npm install -g npm@^2"
install:
- npm install -g bower
- npm install
- bower install
script:
- npm test

3
.watchmanconfig Normal file
View File

@ -0,0 +1,3 @@
{
"ignore_dirs": ["tmp", "dist", "static"]
}

58
README.md Normal file
View File

@ -0,0 +1,58 @@
# Obrand-admin
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
## Prerequisites
You will need the following things properly installed on your computer.
* [Git](http://git-scm.com/)
* [Node.js](http://nodejs.org/) (with NPM)
* [Bower](http://bower.io/)
* [Ember CLI](http://www.ember-cli.com/)
* [PhantomJS](http://phantomjs.org/)
## Installation
* `git clone <repository-url>` this repository
* change into the new directory
* `npm install`
* `bower install`
## Running / Development
* `ember server`
* Visit your app at [http://localhost:4200](http://localhost:4200).
### Code Generators
Make use of the many generators for code, try `ember help generate` for more details
### Running Tests
* `ember test`
* `ember test --server`
### Building
* `ember build` (development)
* `ember build --environment production` (production)
### Deploying
To build do the following:
* `ember build --environtment production`
* copy the contents into the wwwroot folder of obrand-admin-server
* deploy obrand-admin-server
## Further Reading / Useful Links
* [ember.js](http://emberjs.com/)
* [ember-cli](http://www.ember-cli.com/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)

View File

@ -0,0 +1,6 @@
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:application'
});

5
app/adapters/company.js Normal file
View File

@ -0,0 +1,5 @@
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
namespace: 'api'
});

View File

@ -0,0 +1,5 @@
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
namespace: 'api'
});

5
app/adapters/page.js Normal file
View File

@ -0,0 +1,5 @@
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
namespace: 'api'
});

5
app/adapters/profile.js Normal file
View File

@ -0,0 +1,5 @@
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
namespace: 'api'
});

20
app/app.js Normal file
View File

@ -0,0 +1,20 @@
import Ember from 'ember';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
let App;
Ember.MODEL_FACTORY_INJECTIONS = true;
Ember.LOG_TRANSITIONS = true;
Ember.LOG_TRANSITIONS_INTERNAL = true;
App = Ember.Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver
});
loadInitializers(App, config.modulePrefix);
export default App;

View File

@ -0,0 +1,10 @@
/**
*
* User: Martin Donnelly
* Date: 2016-03-04
* Time: 14:23
*
*/
import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant';
export default OAuth2PasswordGrant.extend();

View File

@ -0,0 +1,13 @@
/*
import Base from 'ember-simple-auth/authorizers/base';
export default Base.extend({
authorize(/!*data, block*!/) {
}
});
*/
import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer';
export default OAuth2Bearer.extend();

0
app/components/.gitkeep Normal file
View File

17
app/components/nav-bar.js Normal file
View File

@ -0,0 +1,17 @@
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Component.extend({
session: service('session'), sessionAccount: service('session-account'),
actions: {
login() {
this.sendAction('onLogin');
},
logout() {
this.get('session').invalidate();
}
}
});

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Component.extend({
session: service('session'), sessionAccount: service('session-account')
});

View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Component.extend({
});

0
app/controllers/.gitkeep Normal file
View File

View File

@ -0,0 +1,9 @@
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
transitionToLoginRoute() {
this.transitionToRoute('login');
}
}
});

View File

@ -0,0 +1,29 @@
'use strict';
import Ember from 'ember';
const {service} = Ember.inject;
export default Ember.Controller.extend({
session: service('session'),
sessionAccount: service('session-account'),
actions: {
editCompany: function() {
this.set('isEditing', true);
}, saveCompany: function() {
this.set('isEditing', false);
var model = this.get('model');
model.save()
.catch(function(err) {
console.error(err);
});
}, cancelEdit: function() {
var model = this.get('model');
model.rollbackAttributes();
this.set('isEditing', false);
}
}
});

20
app/controllers/login.js Normal file
View File

@ -0,0 +1,20 @@
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Controller.extend({
session: service('session'),
actions: {
authenticate() {
'use strict';
let {identification, password } = this.getProperties('identification', 'password');
this.get('session').authenticate('authenticator:oauth2', identification, password)
.catch((reason) => {
this.set('errorMessage', reason.error);
});
}
}
});

View File

@ -0,0 +1,24 @@
'use strict';
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Controller.extend({
session: service('session'),
sessionAccount: service('session-account'),
actions: {
saveCompany: function() {
var model = this.get('model');
var account = this.get('sessionAccount.account');
model.set('uid', this.get('sessionAccount.account.uid'));
model.save()
.then(function() {
account.set('memberof', model.get('cid'));
})
.catch(function(err) {
console.error(err);
});
}
}
});

41
app/controllers/pages.js Normal file
View File

@ -0,0 +1,41 @@
import Ember from 'ember';
const { service , store } = Ember.inject;
export default Ember.Controller.extend({
session: service('session'),
sessionAccount: service('session-account'),
actions: {
savePage: function() {
var model = this.get('model');
model.save()
.catch(function(err) {
console.error(err);
});
},
createNew: function() {
'use strict';
const cid = this.get('sessionAccount.account.memberof');
var store = this.get('store');
var newPage = store.createRecord('page',{cid: cid,
vid: 'JPnbDnRzwDSNLTCcS4miFq', content: 0, imageUrl: 'http://lorempixel.com/300/300'});
this.set('content',newPage);
this.set('isEditing', true);
}, cancelEdit: function() {
var model = this.get('model');
model.rollbackAttributes();
model = this.store.findAll('page');
this.set('isEditing', false);
this.set('model', model);
}
}
});

View File

@ -0,0 +1,24 @@
'use strict';
import Ember from 'ember';
const { service } = Ember.inject;
export default Ember.Controller.extend({
session: service('session'),
sessionAccount: service('session-account'),
genders: [{g: 'Male', id: 0}, {g: 'Female', id: 1}],
actions: {
editProfile: function() {
this.set('isEditing', true);
}, saveProfile: function() {
var model = this.get('model');
this.set('sessionAccount.account.forename', model.get('forename'));
this.model.save()
.catch(function(err) {
console.error(err);
});
this.set('isEditing', false);
}
}
});

0
app/helpers/.gitkeep Normal file
View File

9
app/helpers/eq.js Normal file
View File

@ -0,0 +1,9 @@
import Ember from 'ember';
/*export function eq(params/!*, hash*!/) {
return params;
}*/
const eq = (params) => params[0] === params[1];
export default Ember.Helper.helper(eq);

25
app/index.html Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>ObrandAdmin</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{content-for "head"}}
<link rel="stylesheet" href="assets/vendor.css">
<link rel="stylesheet" href="assets/obrand-admin.css">
{{content-for "head-footer"}}
</head>
<body>
{{content-for "body"}}
<script src="assets/vendor.js"></script>
<script src="assets/obrand-admin.js"></script>
{{content-for "body-footer"}}
</body>
</html>

0
app/models/.gitkeep Normal file
View File

14
app/models/account.js Normal file
View File

@ -0,0 +1,14 @@
import DS from 'ember-data';
//const { attr } = DS;
export default DS.Model.extend({
uid: DS.attr('string'),
login: DS.attr('string'),
forename: DS.attr('string'),
surname: DS.attr('string'),
memberof: DS.attr('string'),
fullName: function() {
return '%@ %@'.fmt(this.get('forename'), this.get('surname'));
}.property('forename', 'surname')
});

View File

@ -0,0 +1,5 @@
import DS from 'ember-data';
export default DS.Model.extend({
});

20
app/models/company.js Normal file
View File

@ -0,0 +1,20 @@
import DS from 'ember-data';
export default DS.Model.extend({
cid: DS.attr('string'),
company_name: DS.attr('string'),
address1: DS.attr('string'),
address2: DS.attr('string'),
address3: DS.attr('string'),
town: DS.attr('string'),
county: DS.attr('string'),
postcode: DS.attr('string'),
country: DS.attr('string'),
pcontact: DS.attr('string'),
ocontact: DS.attr('string'),
mobile: DS.attr('string'),
email: DS.attr('string'),
needCompany: function() {
return typeof this.get('cid') !== 'undefined';
}.property('cid')
});

19
app/models/newcompany.js Normal file
View File

@ -0,0 +1,19 @@
import DS from 'ember-data';
export default DS.Model.extend({
uid: DS.attr(),
cid: DS.attr('string'),
company_name: DS.attr('string'),
address1: DS.attr('string'),
address2: DS.attr('string'),
address3: DS.attr('string'),
town: DS.attr('string'),
county: DS.attr('string'),
postcode: DS.attr('string'),
country: DS.attr('string'),
pcontact: DS.attr('string'),
ocontact: DS.attr('string'),
mobile: DS.attr('string'),
email: DS.attr('string')
});

View File

@ -0,0 +1,32 @@
'use strict';
import DS from 'ember-data';
export default DS.Model.extend({
page: DS.belongsTo('page'),
title: DS.attr('string'),
imageUrl: DS.attr('string'),
link1Text: DS.attr('string'),
link1Url: DS.attr('string'),
link2Text: DS.attr('string'),
link2Url: DS.attr('string'),
link3Text: DS.attr('string'),
link3Url: DS.attr('string'),
link4Text: DS.attr('string'),
link4Url: DS.attr('string'),
visibleLink1: function() {
return !((Ember.isBlank(this.get('link1Text'))) || (Ember.isBlank(this.get('link1Url'))));
}.property('link1Url','link1Text'),
visibleLink2: function() {
return !((Ember.isBlank(this.get('link2Text'))) && (Ember.isBlank(this.get('link2Url'))));
}.property('link2Url','link2Text'),
visibleLink3: function() {
return !((Ember.isBlank(this.get('link3Text'))) && (Ember.isBlank(this.get('link3Url'))));
}.property('link3Url','link3Text'),
visibleLink4: function() {
return !((Ember.isBlank(this.get('link4Text'))) && (Ember.isBlank(this.get('link4Url'))));
}.property('link4Url','link4Text'),
noImage: function() {
return Ember.isBlank(this.get('imageUrl'));
}.property('imageUrl')
});

38
app/models/page.js Normal file
View File

@ -0,0 +1,38 @@
import DS from 'ember-data';
export default DS.Model.extend({
cid: DS.attr('string'),
vid: DS.attr('string'),
pid: DS.attr('string'),
category: DS.attr(),
title: DS.attr('string'),
content: DS.attr(),
imageUrl: DS.attr('string'),
link1Text: DS.attr('string'),
link1Url: DS.attr('string'),
link2Text: DS.attr('string'),
link2Url: DS.attr('string'),
link3Text: DS.attr('string'),
link3Url: DS.attr('string'),
link4Text: DS.attr('string'),
link4Url: DS.attr('string'),
visibleLink1: function() {
return !((Ember.isBlank(this.get('link1Text'))) || (Ember.isBlank(this.get('link1Url'))));
}.property('link1Url','link1Text'),
visibleLink2: function() {
return !((Ember.isBlank(this.get('link2Text'))) && (Ember.isBlank(this.get('link2Url'))));
}.property('link2Url','link2Text'),
visibleLink3: function() {
return !((Ember.isBlank(this.get('link3Text'))) && (Ember.isBlank(this.get('link3Url'))));
}.property('link3Url','link3Text'),
visibleLink4: function() {
return !((Ember.isBlank(this.get('link4Text'))) && (Ember.isBlank(this.get('link4Url'))));
}.property('link4Url','link4Text'),
noImage: function() {
return Ember.isBlank(this.get('imageUrl'));
}.property('imageUrl'),
pageMode: function() {
let modeArray = ['Basic Page', 'Other type 1', 'Other type 2', 'Other type 3'];
return modeArray[this.get('content')];
}.property('content')
});

19
app/models/profile.js Normal file
View File

@ -0,0 +1,19 @@
import DS from 'ember-data';
export default DS.Model.extend({
uid: DS.attr('string'),
forename: DS.attr('string'),
surname: DS.attr('string'),
gender: DS.attr('number'),
dob: DS.attr(),
bio: DS.attr('string'),
fullName: function() {
return '%@ %@'.fmt(this.get('forename'), this.get('surname'));
}.property('forename', 'surname'),
qualifiedGender: function() {
let genderArray = ['Male', 'Female'];
return genderArray[this.get('gender')];
}.property('gender')
});

3
app/resolver.js Normal file
View File

@ -0,0 +1,3 @@
import Resolver from 'ember-resolver';
export default Resolver;

21
app/router.js Normal file
View File

@ -0,0 +1,21 @@
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('index', {path:'/'});
this.route('login');
this.route('auth-error');
this.route('about');
this.route('signup');
this.route('profile');
this.route('company');
this.route('newcompany');
this.route('venue');
this.route('pages');
});
export default Router;

0
app/routes/.gitkeep Normal file
View File

4
app/routes/about.js Normal file
View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Route.extend({
});

18
app/routes/application.js Normal file
View File

@ -0,0 +1,18 @@
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
const { service } = Ember.inject;
export default Ember.Route.extend(ApplicationRouteMixin, {
sessionAccount: service('session-account'),
_loadCurrentUser() {
return this.get('sessionAccount').loadCurrentUser();
},
beforeModel() {
return this._loadCurrentUser();
},
sessionAuthenticated() {
this._super(...arguments);
this._loadCurrentUser().catch(() => this.get('session').invalidate());
}
});

8
app/routes/auth-error.js Normal file
View File

@ -0,0 +1,8 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model() {
return this.get('store').find('post', 3);
}
});

33
app/routes/company.js Normal file
View File

@ -0,0 +1,33 @@
import Ember from 'ember';
const { inject: { service }, RSVP } = Ember;
export default Ember.Route.extend({
sessionAccount: service('session-account'),
beforeModel() {
const cid = this.get('sessionAccount.account.memberof');
if (typeof cid === 'undefined' || cid === null) {
this.transitionTo('newcompany');
}
},
model: function() {
'use strict';
const cid = this.get('sessionAccount.account.memberof');
if (typeof cid !== 'undefined' && cid !== null) {
return new RSVP.Promise((resolve, reject) => {
return this.get('store').find('company', cid)
.then(resolve, reject);
});
} else {
return {
needNewCompany: true
};
}
}
});

4
app/routes/index.js Normal file
View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Route.extend({
});

6
app/routes/login.js Normal file
View File

@ -0,0 +1,6 @@
import Ember from 'ember';
import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin';
export default Ember.Route.extend(UnauthenticatedRouteMixin);

23
app/routes/newcompany.js Normal file
View File

@ -0,0 +1,23 @@
import Ember from 'ember';
const { inject: { service }, RSVP } = Ember;
export default Ember.Route.extend({
sessionAccount: service('session-account'),
model: function() {
'use strict';
const cid = this.get('sessionAccount.account.memberOf');
if (typeof cid !== 'undefined') {
return new RSVP.Promise((resolve, reject) => {
return this.get('store').find('company', cid)
.then(resolve, reject);
});
} else {
var newPage = this.store.createRecord('newcompany',{});
newPage.set('cid', cid);
return newPage;
}
}
});

17
app/routes/pages.js Normal file
View File

@ -0,0 +1,17 @@
import Ember from 'ember';
const { inject: { service } } = Ember;
export default Ember.Route.extend({
sessionAccount: service('session-account'),
beforeModel() {
'use strict';
const cid = this.get('sessionAccount.account.memberof');
this.store.query('page', { filter: { cid: cid } }).then(function(d) {
return d;
});
},
model: function() {
return this.store.findAll('page');
}
});

18
app/routes/profile.js Normal file
View File

@ -0,0 +1,18 @@
import Ember from 'ember';
const { inject: { service }, RSVP } = Ember;
export default Ember.Route.extend({
sessionAccount: service('session-account'),
model: function() {
'use strict';
const accountId = this.get('sessionAccount.account.id');
return new RSVP.Promise((resolve,reject) => {
return this.get('store').find('profile',accountId)
.then(resolve,reject);
});
}
});

4
app/routes/signup.js Normal file
View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Route.extend({
});

12
app/routes/venue.js Normal file
View File

@ -0,0 +1,12 @@
import Ember from 'ember';
const { inject: { service } } = Ember;
export default Ember.Route.extend({
sessionAccount: service('session-account'),
beforeModel() {
const cid = this.get('sessionAccount.account.memberof');
if (typeof cid === 'undefined') {
this.transitionTo('newcompany');
}
}
});

37
app/serializers/useful.js Normal file
View File

@ -0,0 +1,37 @@
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key,
belongsTo = Ember.get(record, key);
key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key;
if (relationship.options.embedded === 'always') {
json[key] = belongsTo.serialize();
}
else {
return this._super(record, json, relationship);
}
},
serializeHasMany: function(record, json, relationship) {
var key = relationship.key,
hasMany = Ember.get(record, key),
relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationship.options.embedded === 'always') {
if (hasMany && relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') {
json[key] = [];
hasMany.forEach(function(item, index){
json[key].push(item.serialize());
});
}
}
else {
return this._super(record, json, relationship);
}
}
});

View File

@ -0,0 +1,24 @@
import Ember from 'ember';
const { inject: { service }, RSVP } = Ember;
export default Ember.Service.extend({
session: service('session'),
store: service(),
loadCurrentUser() {
return new RSVP.Promise((resolve, reject) => {
const accountId = this.get('session.data.authenticated.account_id');
if (!Ember.isEmpty(accountId)) {
return this.get('store').find('account', accountId).then((account) => {
this.set('account', account);
return resolve();
}, reject);
} else {
return resolve();
}
});
}
});

59
app/styles/app.scss Normal file
View File

@ -0,0 +1,59 @@
@import 'bootstrap';
/*@import 'signin';*/
/*@import 'profile';*/
@import 'side-bar';
$input-border-focus: #ff0000 !default;
body {
padding-top:5em;
}
.app-top {
padding: 3rem 1.5rem;
}
.colour-bg {
color: #fff;
/*background: linear-gradient(-226deg, rgba(142, 130, 236, 0.8) 0%, rgba(8, 81, 152, 0.92) 100%);*/
position: relative;
display: block;
padding: 200px 40px;
height: 500px;
width: 100%;
}
.blue-tint {
background: linear-gradient(-226deg, rgba(142, 130, 236, 0.8) 0%, rgba(8, 81, 152, 0.92) 100%);
}
.user-icon-nav {
margin-right:10px;
}
.dropdown-menu{
padding:5px 0;
margin:2px 0 0;
}
.fakeDevice{
width: 375px;
height: 667px;
border:1px solid grey;
-webkit-box-shadow: 0px 4px 5px 0px rgba(0,0,0,0.43);
-moz-box-shadow: 0px 4px 5px 0px rgba(0,0,0,0.43);
box-shadow: 0px 4px 5px 0px rgba(0,0,0,0.43);
border-radius: 0.25rem;
}
.image300 {
max-width: 300px;
max-height: 300px;
}

22
app/styles/profile.scss Normal file
View File

@ -0,0 +1,22 @@
/* CSS used here will be applied after bootstrap.css */
body {
/*background-color: #eaeaea;*/
}
img.avatar {
border: 1px solid #eee;
}
.only-bottom-margin {
margin-top: 0px;
}
.activity-mini {
padding-right: 15px;
float: left;
}
.profileCard {
box-shadow:0 1px 2px #aaa;
}

341
app/styles/side-bar.scss Normal file
View File

@ -0,0 +1,341 @@
h1.page-header {
margin-top: -5px;
}
.sidebar {
padding-left: 0;
}
.main-container {
background: #FFF;
padding-top: 15px;
margin-top: -20px;
}
.footer {
width: 100%;
}
:focus {
outline: none;
}
.side-menu {
position: relative;
width: 100%;
height: 100%;
background-color: #f8f8f8;
border-right: 1px solid #e7e7e7;
}
.side-menu .navbar {
border: none;
}
.side-menu .navbar-header {
width: 100%;
border-bottom: 1px solid #e7e7e7;
}
.side-menu .navbar-nav .active a {
background-color: transparent;
margin-right: -1px;
border-right: 5px solid #e7e7e7;
}
.side-menu .navbar-nav li {
display: block;
width: 100%;
border-bottom: 1px solid #e7e7e7;
}
.side-menu .navbar-nav li a {
padding: 15px;
}
.side-menu .navbar-nav li a .glyphicon {
padding-right: 10px;
}
.side-menu #dropdown {
border: 0;
margin-bottom: 0;
border-radius: 0;
background-color: transparent;
box-shadow: none;
}
.side-menu #dropdown .caret {
float: right;
margin: 9px 5px 0;
}
.side-menu #dropdown .indicator {
float: right;
}
.side-menu #dropdown > a {
border-bottom: 1px solid #e7e7e7;
}
.side-menu #dropdown .panel-body {
padding: 0;
background-color: #f3f3f3;
}
.side-menu #dropdown .panel-body .navbar-nav {
width: 100%;
}
.side-menu #dropdown .panel-body .navbar-nav li {
padding-left: 15px;
border-bottom: 1px solid #e7e7e7;
}
.side-menu #dropdown .panel-body .navbar-nav li:last-child {
border-bottom: none;
}
.side-menu #dropdown .panel-body .panel > a {
margin-left: -20px;
padding-left: 35px;
}
.side-menu #dropdown .panel-body .panel-body {
margin-left: -15px;
}
.side-menu #dropdown .panel-body .panel-body li {
padding-left: 30px;
}
.side-menu #dropdown .panel-body .panel-body li:last-child {
border-bottom: 1px solid #e7e7e7;
}
.side-menu #search-trigger {
background-color: #f3f3f3;
border: 0;
border-radius: 0;
position: absolute;
top: 0;
right: 0;
padding: 15px 18px;
}
.side-menu .brand-name-wrapper {
min-height: 50px;
}
.side-menu .brand-name-wrapper .navbar-brand {
display: block;
}
.side-menu #search {
position: relative;
z-index: 1000;
}
.side-menu #search .panel-body {
padding: 0;
}
.side-menu #search .panel-body .navbar-form {
padding: 0;
padding-right: 50px;
width: 100%;
margin: 0;
position: relative;
border-top: 1px solid #e7e7e7;
}
.side-menu #search .panel-body .navbar-form .form-group {
width: 100%;
position: relative;
}
.side-menu #search .panel-body .navbar-form input {
border: 0;
border-radius: 0;
box-shadow: none;
width: 100%;
height: 50px;
}
.side-menu #search .panel-body .navbar-form .btn {
position: absolute;
right: 0;
top: 0;
border: 0;
border-radius: 0;
background-color: #f3f3f3;
padding: 15px 18px;
}
/* Main body section */
.side-body {
margin-left: 310px;
}
/* small screen */
@media (max-width: 768px) {
.side-menu {
position: relative;
width: 100%;
height: 0;
border-right: 0;
}
.side-menu .navbar {
z-index: 999;
position: relative;
height: 0;
min-height: 0;
background-color:none !important;
border-color: none !important;
}
.side-menu .brand-name-wrapper .navbar-brand {
display: inline-block;
}
/* Slide in animation */
@-moz-keyframes slidein {
0% {
left: -300px;
}
100% {
left: 10px;
}
}
@-webkit-keyframes slidein {
0% {
left: -300px;
}
100% {
left: 10px;
}
}
@keyframes slidein {
0% {
left: -300px;
}
100% {
left: 10px;
}
}
@-moz-keyframes slideout {
0% {
left: 0;
}
100% {
left: -300px;
}
}
@-webkit-keyframes slideout {
0% {
left: 0;
}
100% {
left: -300px;
}
}
@keyframes slideout {
0% {
left: 0;
}
100% {
left: -300px;
}
}
/* Slide side menu*/
/* Add .absolute-wrapper.slide-in for scrollable menu -> see top comment */
.side-menu-container > .navbar-nav.slide-in {
-moz-animation: slidein 300ms forwards;
-o-animation: slidein 300ms forwards;
-webkit-animation: slidein 300ms forwards;
animation: slidein 300ms forwards;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.side-menu-container > .navbar-nav {
/* Add position:absolute for scrollable menu -> see top comment */
position: fixed;
left: -300px;
width: 300px;
top: 43px;
height: 100%;
border-right: 1px solid #e7e7e7;
background-color: #f8f8f8;
overflow: auto;
-moz-animation: slideout 300ms forwards;
-o-animation: slideout 300ms forwards;
-webkit-animation: slideout 300ms forwards;
animation: slideout 300ms forwards;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
@-moz-keyframes bodyslidein {
0% {
left: 0;
}
100% {
left: 300px;
}
}
@-webkit-keyframes bodyslidein {
0% {
left: 0;
}
100% {
left: 300px;
}
}
@keyframes bodyslidein {
0% {
left: 0;
}
100% {
left: 300px;
}
}
@-moz-keyframes bodyslideout {
0% {
left: 300px;
}
100% {
left: 0;
}
}
@-webkit-keyframes bodyslideout {
0% {
left: 300px;
}
100% {
left: 0;
}
}
@keyframes bodyslideout {
0% {
left: 300px;
}
100% {
left: 0;
}
}
/* Slide side body*/
.side-body {
margin-left: 5px;
margin-top: 70px;
position: relative;
-moz-animation: bodyslideout 300ms forwards;
-o-animation: bodyslideout 300ms forwards;
-webkit-animation: bodyslideout 300ms forwards;
animation: bodyslideout 300ms forwards;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.body-slide-in {
-moz-animation: bodyslidein 300ms forwards;
-o-animation: bodyslidein 300ms forwards;
-webkit-animation: bodyslidein 300ms forwards;
animation: bodyslidein 300ms forwards;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
/* Hamburger */
.navbar-toggle-sidebar {
border: 0;
float: left;
padding: 18px;
margin: 0;
border-radius: 0;
background-color: #f3f3f3;
}
/* Search */
#search .panel-body .navbar-form {
border-bottom: 0;
}
#search .panel-body .navbar-form .form-group {
margin: 0;
}
.side-menu .navbar-header {
/* this is probably redundant */
position: fixed;
z-index: 3;
background-color: #f8f8f8;
}
/* Dropdown tweek */
#dropdown .panel-body .navbar-nav {
margin: 0;
}
}

42
app/styles/signin.scss Normal file
View File

@ -0,0 +1,42 @@
.form-signin {
max-width:330px;
padding:15px;
margin:0 auto;
box-shadow:0 1px 2px #aaa;
border-radius:3px;
user-select:none;
}
.form-signin .form-signin-heading, .form-signin .checkbox {
margin-bottom:10px;
}
.form-signin .checkbox {
font-weight:normal;
}
.form-signin .form-control {
position:relative;
height:auto;
-webkit-box-sizing:border-box;
box-sizing: border-box;
padding:10px;
font-size:16px;
}
.form-signin .form-control:focus{
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom:-1px;
border-bottom-right-radius:0;
border-bottom-left-radius:0;
}
.form-signin input[type='password'] {
margin-bottom:10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}

6
app/templates/about.hbs Normal file
View File

@ -0,0 +1,6 @@
<div class="jumbotron">
<div class="container">
<h1>Welcome to OBrand</h1>
<p>Warm and welcoming text about oBrand</p>
</div>
</div>

View File

@ -0,0 +1,14 @@
{{nav-bar currentControllerBindings="controller"}}
<div class="container-fluid main-container" class="app-body">
{{outlet}}
<footer class="pull-left footer">
<p class="col-md-12">
<hr class="divider">
Copyright &COPY; 2016 <a
href="http://www.obrand.info">Obrand Communications</a> </p>
</footer>
</div>

View File

@ -0,0 +1 @@
{{outlet}}

156
app/templates/company.hbs Normal file
View File

@ -0,0 +1,156 @@
<!--<div class="container profileCard">-->
<div class="container profileCard">
{{#if isEditing}}
<form {{action "saveCompany" on='submit'}} class="form-horizontal">
<div class="form-group">
<label for="company_name"
class="col-sm-2 control-label">Company name:</label>
<div class="col-sm-10">
{{input id='company_name' placeholder='Company name' value=model.company_name class="form-control" required="required"}}
</div>
</div>
<br/>
<div class="form-group">
<label for="address1" class="col-sm-2 control-label">Address:</label>
<div class="col-sm-10">
{{input id='address1' placeholder='Address' value=model.address1 class="form-control" required="required"}}
{{input id='address2' placeholder='Address' value=model.address2 class="form-control" }}
{{input id='address3' placeholder='Address' value=model.address3 class="form-control" }}
</div>
</div>
<br/>
<!-- -->
<div class="form-group">
<label for="town" class="col-sm-2 control-label">Town:</label>
<div class="col-sm-10">
{{input id='town' placeholder='Town' value=model.town class="form-control" required="required"}}
</div>
<!-- -->
<label for="county" class="col-sm-2 control-label">County:</label>
<div class="col-sm-10">
{{input id='county' placeholder='County' value=model.county class="form-control" }}
</div>
<!-- -->
<label for="postcode" class="col-sm-2 control-label">Postcode:</label>
<div class="col-sm-10">
{{input id='postcode' placeholder='Postcode' value=model.postcode class="form-control" required="required"}}
</div>
</div>
<br/>
<div class="form-group">
<label for="pcontact"
class="col-sm-2 control-label">Primary Contact:</label>
<div class="col-sm-10">
{{input id='pcontact' placeholder='Primary contact number' value=model.pcontact class="form-control" required="required"}}
</div>
<label for="ocontact"
class="col-sm-2 control-label">Other Contact:</label>
<div class="col-sm-10">
{{input id='ocontact' placeholder='Other contact phone number' value=model.ocontact class="form-control" }}
</div>
<label for="mobile" class="col-sm-2 control-label">Mobile:</label>
<div class="col-sm-10">
{{input id='mobile' placeholder='Mobile phone' value=model.mobile class="form-control" }}
</div>
</div>
<br/>
<div class="form-group">
<label for="email" class="col-sm-2 control-label">Email:</label>
<div class="col-sm-10">
{{input id='email' placeholder='Contact email address' value=model.email class="form-control" required="required"}}
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-8">&nbsp;</div>
<div class="col-md-4">
{{#if isEditing}}
<button class="btn btn-primary pull-right" type="submit">
<i class="glyphicon glyphicon-pencil"></i> Save
</button>
&nbsp;
<button class="btn btn-warning-outline pull-right" {{action "cancelEdit"}}>
Cancel
</button>
{{/if}}
</div>
</div>
</div>
</form>
{{else}}
<h1 class="only-bottom-margin">{{model.company_name}}</h1>
<div class="row">
<div class="col-sm-2">Address</div>
<div class="col-sm-10">
<div>{{model.address1}}</div>
<div>{{model.address2}}</div>
<div>{{model.address3}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Town</div>
<div class="col-sm-10">
<div>{{model.town}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">County</div>
<div class="col-sm-10">
<div>{{model.county}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Postcode</div>
<div class="col-sm-10">
<div>{{model.postcode}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Primary contact</div>
<div class="col-sm-10">
<div>{{model.pcontact}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Secondary contact</div>
<div class="col-sm-10">
<div>{{model.ocontact}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Mobile</div>
<div class="col-sm-10">
<div>{{model.mobile}}</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">Email</div>
<div class="col-sm-10">
<div>{{model.email}}</div>
</div>
</div>
{{/if}}
<div class="form-group">
<div class="row">
<div class="col-md-12">
{{#if isEditing}}
{{else}}
<button class="btn btn-default pull-right" {{action "editCompany"}}>
<i class="glyphicon glyphicon-pencil"></i> Edit
</button>
&nbsp;
{{/if}}
</div>
</div>
</div>
</div>

View File

View File

@ -0,0 +1,52 @@
<!--<nav class="navbar navbar-fixed-top navbar-dark bg-inverse">-->
<nav class="navbar navbar-light bg-faded navbar-fixed-top">
<div class="collapse navbar-toggleable-xs">
<a class="navbar-brand" href="#">OBrand Admin</a>
<ul class="nav navbar-nav">
<li class="nav-item">
{{#link-to 'index' class='nav-link'}}Home{{/link-to}}
</li>
<li class="nav-item">
{{#link-to 'about' class='nav-link'}}About{{/link-to}}
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
{{#if session.isAuthenticated}}
<li class="nav-item">
{{#link-to 'profile' class='nav-link'}}Profile{{/link-to}}
</li>
<li class="nav-item">
{{#link-to 'company' class='nav-link'}}Company{{/link-to}}
</li>
<li class="nav-item">
{{#link-to 'venue' class='nav-link'}}Venues{{/link-to}}
</li>
<li class="nav-item">
<a class="nav-link" href="#">Beacons</a>
</li>
<li class="nav-item">
{{#link-to 'pages' class='nav-link'}}Pages{{/link-to}}
</li>
{{/if}}
</ul>
<div class="pull-xs-right">
{{#if sessionAccount.account}}
<span
class="nav-item">{{gravatar-image email=sessionAccount.account.login size=25 class="img-circle avatar avatar-original pull-right user-icon-nav" defaultImage='identicon'}}
<span class="text-primary">{{sessionAccount.account.forename}}</span></span>
<span class="navbar-divider"></span>
{{/if}}
<span class="nav-item">
{{#if session.isAuthenticated}}
<a {{action 'logout'}} class="btn btn-danger-outline">Logout</a>
{{else}}
{{#link-to 'login' class='btn btn-primary-outline'}}Login{{/link-to}}
{{/if}}
</span>
</div>
</div>
</nav>

View File

@ -0,0 +1,29 @@
<div class="container-fluid main-container">
<div class="col-md-12 content">
<div class="card">
<div class="card-header">
New Page
</div>
<div class="card-block">
<div class="row">
<div class="col-md-4 content">
Entered content
</div>
<div class="col-md-8 content">
<div id="fakeDevice" class="fakeDevice">
<h1 class="text-xs-center">OBrand Test</h1>
<img src="http://placehold.it/300x300" class="center-block"/>
<ul class="list-group">
<li class="list-group-item">List item 1</li>
<li class="list-group-item">List item 2</li>
<li class="list-group-item">List item 3</li>
<li class="list-group-item">List item 4</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,65 @@
<!-- trying to implement the menu from
http://bootsnipp.com/snippets/featured/simple-admin
-->
<div class="col-md-2 sidebar">
<div class="row">
<div class="absolute-wrapper"></div>
<div class="side-menu">
<nav class="navbar navbar-default" role="navigation">
<!-- Main Menu -->
<div class="side-menu-container">
<ul class="nav navbar-nav">
<li class="active"><a href="#"><span
class="glyphicon glyphicon-dashboard"></span> Dashboard</a></li>
<li><a href="#"><span
class="glyphicon glyphicon-plane"></span> Active Link</a></li>
<li><a href="#"><span
class="glyphicon glyphicon-cloud"></span> Link</a></li>
<!-- Dropdown-->
<li class="panel panel-default" id="dropdown">
<a data-toggle="collapse" href="#dropdown-lvl1"> <span
class="glyphicon glyphicon-user"></span> Sub Level <span
class="caret"></span> </a>
<!-- Dropdown level 1 -->
<div id="dropdown-lvl1" class="panel-collapse collapse">
<div class="panel-body">
<ul class="nav navbar-nav">
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<!-- Dropdown level 2 -->
<li class="panel panel-default" id="dropdown">
<a data-toggle="collapse" href="#dropdown-lvl2"> <span
class="glyphicon glyphicon-off"></span> Sub Level
<span class="caret"></span> </a>
<div id="dropdown-lvl2" class="panel-collapse collapse">
<div class="panel-body">
<ul class="nav navbar-nav">
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</ul>
</div>
</div>
</li>
</ul>
</div>
</div>
</li>
<li><a href="#"><span
class="glyphicon glyphicon-signal"></span> Link</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</nav>
</div>
</div>
</div>

15
app/templates/index.hbs Normal file
View File

@ -0,0 +1,15 @@
{{#unless session.isAuthenticated}}
<div class="alert alert-info">
You can {{#link-to 'login' classNames='alert-link'}}log in{{/link-to}} with login <code>m@g.com</code> and password <code>password</code>.
</div>
{{/unless}}
<div class="jumbotron">
<div class="container" style="background: linear-gradient(-226deg, rgba(142, 130, 236, 0.8) 0%, rgba(8, 81, 152, 0.92) 100%),url('images/skyview.jpg');background-size:100%;">
<span class="colour-bg">
<h1>Welcome to OBrand</h1>
<p>Warm and welcoming text about oBrand</p>
</span>
</div>
</div>

40
app/templates/login.hbs Normal file
View File

@ -0,0 +1,40 @@
<form class="form-signin" {{action 'authenticate' on='submit'}}>
<div>
<h2 class="form-signin-heading">Please login</h2>
<label for="inputEmail" class="sr-only">Email address</label>
{{input type='email' required="required" autofocus="autofocus" id='inputEmail' placeholder='Email address' value=identification class="form-control" }}
<label for="inputPassword" class="sr-only">Password</label>
{{input id='inputPassword' placeholder='Password' type='password' value=password class="form-control" required="required"}}
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button type='submit' class="btn btn-lg btn-primary btn-block">Login</button>
</div>
{{#if errorMessage}}
<div class="alert alert-danger" role="alert">{{errorMessage}}</div>
<div class="alert alert-info">
If you don't have an account, click <strong>SIGN UP</strong> and create one now.
</div>
{{/if}}
</form>
<!--
<h2 class="form-signin-heading">Please login</h2>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit"></button>
-->

View File

@ -0,0 +1,62 @@
<!--<div class="container profileCard">-->
<div class="container profileCard">
<form {{action "saveCompany" on='submit'}} class="form-horizontal">
<div class="form-group">
<label for="company_name" class="col-sm-2 control-label">Company name:</label>
<div class="col-sm-10">
{{input id='company_name' placeholder='Company name' value=model.company_name class="form-control" required="required"}}
</div>
</div>
<br/>
<div class="form-group">
<label for="address1" class="col-sm-2 control-label">Address:</label>
<div class="col-sm-10">
{{input id='address1' placeholder='Address' value=model.address1 class="form-control" required="required"}}
{{input id='address2' placeholder='Address' value=model.address2 class="form-control" }}
{{input id='address3' placeholder='Address' value=model.address3 class="form-control" }}
</div>
</div>
<br/>
<div class="form-group">
<label for="town" class="col-sm-2 control-label">Town:</label>
<div class="col-sm-10">
{{input id='town' placeholder='Town' value=model.town class="form-control" required="required"}}
</div>
<label for="county" class="col-sm-2 control-label">County:</label>
<div class="col-sm-10">
{{input id='county' placeholder='County' value=model.county class="form-control" }}
</div>
<label for="postcode" class="col-sm-2 control-label">Postcode:</label>
<div class="col-sm-10">
{{input id='postcode' placeholder='Postcode' value=model.postcode class="form-control" required="required"}}
</div>
</div>
<br/>
<div class="form-group">
<label for="pcontact" class="col-sm-2 control-label">Primary Contact:</label>
<div class="col-sm-10">
{{input id='pcontact' placeholder='Primary contact number' value=model.pcontact class="form-control" required="required"}}
</div>
<label for="ocontact" class="col-sm-2 control-label">Other Contact:</label>
<div class="col-sm-10">
{{input id='ocontact' placeholder='Other contact phone number' value=model.ocontact class="form-control" }}
</div>
<label for="mobile" class="col-sm-2 control-label">Mobile:</label>
<div class="col-sm-10">
{{input id='mobile' placeholder='Mobile phone' value=model.mobile class="form-control" }}
</div>
</div>
<br/>
<div class="form-group">
<label for="email" class="col-sm-2 control-label">Email:</label>
<div class="col-sm-10">
{{input id='email' placeholder='Contact email address' value=model.email class="form-control" required="required"}}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Save</button>
</div>
</div>
</form>
</div>

156
app/templates/pages.hbs Normal file
View File

@ -0,0 +1,156 @@
<div class="container-fluid main-container">
<div class="col-md-12 content">
<div class="card">
<div class="card-block">
<div class="row">
<div class="col-md-4 content">
<button
class="btn btn-primary-outline" {{action "createNew"}}>Create a new basic page
</button>
</div>
</div>
</div>
</div>
{{#unless isEditing}}
<div class="card">
<div class="card-block">
{{#each model as |item|}}
<div class="row">
<div class="col-md-4 content">
{{item.title}}
</div>
<div class="col-md-4 content">
{{item.pageMode}}
</div>
<div class="col-md-4 content">
<button class="btn btn-primary btn-sm">Edit</button>
<button class="btn btn-danger btn-sm">Delete</button>
</div>
</div>
{{/each}}
</div>
</div>
{{/unless}}
{{#if isEditing}}
<div class="card">
<div class="card-header">
New Page
</div>
<div class="card-block">
<div class="row">
<div class="col-md-4 content">
<form {{action "savePage" on='submit'}}>
<div class="col-md-12 form-inline">
<label for="title">Title:</label>
{{input id='title' placeholder='title' value=model.title class="form-control" required="required"}}
</div>
<div class="col-md-12 form-inline">
<label for="imageUrl">Image URL:</label>
{{input id='imageUrl' placeholder='URL to your image' value=model.imageUrl class="form-control" required="required"}}
</div>
<div class="col-md-12 form-inline">
<div>Link One</div>
<label for="link1title">Text:</label>
{{input id='link1title' placeholder='Text' value=model.link1Text class="form-control"}}
<label for="link1url">URL:</label>
{{input id='link1url' placeholder='http://something.com/link' value=model.link1Url class="form-control"}}
</div>
<div class="col-md-12 form-inline">
<div>Link Two</div>
<label for="link2title">Text:</label>
{{input id='link2title' placeholder='Text' value=model.link2Text class="form-control"}}
<label for="link2url">URL:</label>
{{input id='link2url' placeholder='http://something.com/link' value=model.link2Url class="form-control"}}
</div>
<div class="col-md-12 form-inline">
<div>Link Three</div>
<label for="link3title">Text:</label>
{{input id='link3title' placeholder='Text' value=model.link3Text class="form-control"}}
<label for="link3url">URL:</label>
{{input id='link3url' placeholder='http://something.com/link' value=model.link3Url class="form-control"}}
</div>
<div class="col-md-12 form-inline">
<div>Link Four</div>
<label for="link4title">Text:</label>
{{input id='link4title' placeholder='Text' value=model.link4Text class="form-control"}}
<label for="link4url">URL:</label>
{{input id='link4url' placeholder='http://something.com/link' value=model.link4Url class="form-control"}}
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Save</button>
<button
class="btn btn-danger" {{action "cancelEdit"}}>Cancel
</button>
</div>
</div>
</form>
</div>
<div></div>
<div class="col-md-8 content">
<div id="fakeDevice" class="fakeDevice">
<h1 class="text-xs-center">{{ model.title }}</h1>
{{#if model.noImage }}
<img src="http://pipes.silvrtree.co.uk/assets/fm.png"
class="center-block image300"/>
{{else}}
<img src="{{model.imageUrl}}" class="center-block image300"/>
{{/if}}
<ul class="list-group">
{{#if model.visibleLink1 }}
<li class="list-group-item text-xs-center"><a
href="{{model.link1Url}}"
target="_blank">{{model.link1Text}}</a></li>
{{else}}
<li class="list-group-item text-muted text-xs-center">
<em>Your link here</em></li>
{{/if}}
{{#if model.visibleLink2 }}
<li class="list-group-item text-xs-center"><a
href="{{model.link2Url}}"
target="_blank">{{model.link2Text}}</a>
</li>
{{else}}
<li class="list-group-item text-muted text-xs-center">
<em>Your link here</em></li>
{{/if}}
{{#if model.visibleLink3 }}
<li class="list-group-item text-xs-center"><a
href="{{model.link3Url}}"
target="_blank">{{model.link3Text}}</a>
</li>
{{else}}
<li class="list-group-item text-muted text-xs-center">
<em>Your link here</em></li>
{{/if}}
{{#if model.visibleLink4 }}
<li class="list-group-item text-xs-center"><a
href="{{model.link4Url}}"
target="_blank">{{model.link4Text}}</a>
</li>
{{else}}
<li class="list-group-item text-muted text-xs-center">
<em>Your link here</em></li>
{{/if}}
</ul>
</div>
</div>
</div>
</div>
</div>
{{/if}}
</div>
</div>

143
app/templates/profile.hbs Normal file
View File

@ -0,0 +1,143 @@
<div class="container profileCard">
<form {{action "saveProfile" on='submit'}}>
<div class="row">
<div class="col-md-*">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-md-12 lead">User profile
<hr>
</div>
</div>
<div class="row">
<div class="col-md-4 text-center">
<!--<img class="img-circle avatar avatar-original"
style="-webkit-user-select:none;
display:block; margin:auto;"
src="http://robohash.org/sitsequiquia.png?size=120x120">-->
{{gravatar-image email=sessionAccount.account.login size=120 class="img-circle avatar avatar-original pull-right" defaultImage='identicon'}}
</div>
<div class="col-md-8">
<div class="row">
<div class="col-md-12 form-inline">
{{#if isEditing}}
<label for="forename">Forename:</label>
{{input id='forename' placeholder='Forename' value=model.forename class="form-control" required="required"}}
<label for="surname">Surname:</label>
{{input id='surname' placeholder='Surname' value=model.surname class="form-control" required="required"}}
{{else}}
<h1 class="only-bottom-margin">{{model.fullName}}</h1>
{{/if}}
</div>
</div>
<div class="row">
<div class="col-md-6">
<div>
<span
class="text-muted">Email:</span> {{sessionAccount.account.login}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<!-- Start dob -->
{{#if isEditing}}
<div class="form-group form-inline">
<label for="dob">Birth date:</label>
{{input id='dob' type='date' value=model.dob class="form-control" required="required"}}
</div>
{{else}}
<div><span class="text-muted">Birth date:</span>
{{moment-format model.dob 'MMM Do \'YY'}}
</div>
{{/if}}
<!-- End dob -->
</div>
</div>
<!-- Start Gender -->
<div class="row">
<div class="col-md-6">
<div>
{{#if isEditing}}
<div class="form-group form-inline">
<label for="gender">Gender:</label> <select
value={{model.gender}} class="form-control">
{{#each genders as |gender|}}
<option
value={{gender.id}} selected={{eq model.gender gender.id}} >{{gender.g}}</option>
{{/each}}
</select>
</div>
{{else}}
<div><span
class="text-muted">Gender:</span> {{model.qualifiedGender}}
</div>
{{/if}}
</div>
</div>
<!-- End Gender --><br><br>
</div>
<div class="row">
<div class="col-lg-9">
<div>
{{#if isEditing}}
<div class="form-group">
<!--<label for="bio">Bio:</label> <textarea id="bio" value=model.bio
class="form-control">{{model.bio}}</textarea>-->
{{textarea id=bio value=model.bio class="form-control"}}
</div>
{{else}}
<div>
<small class="text-muted">{{model.bio}}</small>
</div>
{{/if}}
</div>
</div>
</div>
</div>
<!--<div class="col-md-6">
<div class="activity-mini">
<i class="glyphicon glyphicon-comment text-muted"></i> 500
</div>
<div class="activity-mini">
<i class="glyphicon glyphicon-thumbs-up text-muted"></i> 1500
</div>
</div>-->
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<hr>
<button class="btn btn-default pull-right" {{action "editProfile"}}>
<i class="glyphicon glyphicon-pencil"></i> Edit
</button>
&nbsp;
{{#if isEditing}}
<button class="btn btn-primary pull-right" type="submit">
<i class="glyphicon glyphicon-pencil"></i> Save
</button>
{{/if}}
</div>
</div>
<div>
{{#if isEditing}}
<p>EDITING MODE!!!</p>
{{/if}}
</div>
</div>
</div>
</form>
</div>
<div></div>

1
app/templates/signup.hbs Normal file
View File

@ -0,0 +1 @@
{{outlet}}

1
app/templates/venue.hbs Normal file
View File

@ -0,0 +1 @@
{{outlet}}

13
bower.json Normal file
View File

@ -0,0 +1,13 @@
{
"name": "obrand-admin",
"dependencies": {
"ember": "~2.4.1",
"ember-cli-shims": "0.1.0",
"ember-cli-test-loader": "0.2.2",
"ember-qunit-notifications": "0.1.0",
"tether": "^1.2.0",
"lodash": "~3.7.0",
"JavaScript-MD5": "^2.3.0",
"blueimp-md5": "2.1.0"
}
}

52
config/environment.js Normal file
View File

@ -0,0 +1,52 @@
/* jshint node: true */
module.exports = function(environment) {
var ENV = {
modulePrefix: 'obrand-admin',
environment: environment,
baseURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. 'with-controller': true
}
},
APP: {
// Here you can pass flags/options to your application instance
// when it is created
},
contentSecurityPolicy: {
'style-src': "'self' 'unsafe-inline'",
'img-src':"'self' www.gravatar.com"
}
};
if (environment === 'development') {
// ENV.APP.LOG_RESOLVER = true;
ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
ENV.APP.LOG_VIEW_LOOKUPS = true;
}
if (environment === 'test') {
// Testem prefers this...
ENV.baseURL = '/';
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
}
if (environment === 'production') {
}
return ENV;
};

25
ember-cli-build.js Normal file
View File

@ -0,0 +1,25 @@
/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
// Add options here
});
app.import('bower_components/blueimp-md5/js/md5.js');
// Use `app.import` to add additional libraries to the generated
// output files.
//
// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.
return app.toTree();
};

67
package.json Normal file
View File

@ -0,0 +1,67 @@
{
"name": "obrand-admin",
"version": "0.0.0",
"description": "Small description for obrand-admin goes here",
"private": true,
"directories": {
"doc": "doc",
"test": "tests"
},
"scripts": {
"build": "ember build",
"start": "ember server",
"test": "ember test"
},
"repository": "",
"engines": {
"node": ">= 0.10.0"
},
"author": "",
"license": "MIT",
"devDependencies": {
"bcrypt-as-promised": "^1.1.0",
"body-parser": "^1.15.0",
"broccoli-asset-rev": "^2.2.0",
"ember-ajax": "0.7.1",
"ember-bootstrap-4": "0.1.0",
"ember-cli": "2.4.1",
"ember-cli-app-version": "^1.0.0",
"ember-cli-babel": "^5.1.5",
"ember-cli-dependency-checker": "^1.2.0",
"ember-cli-gravatar": "3.5.0",
"ember-cli-htmlbars": "^1.0.1",
"ember-cli-htmlbars-inline-precompile": "^0.3.1",
"ember-cli-inject-live-reload": "^1.3.1",
"ember-cli-md5": "^0.1.0",
"ember-cli-moment-shim": "1.1.0",
"ember-cli-qunit": "^1.2.1",
"ember-cli-release": "0.2.8",
"ember-cli-sass": "5.3.0",
"ember-cli-sri": "^2.1.0",
"ember-cli-uglify": "^1.2.0",
"ember-data": "^2.4.0",
"ember-disable-proxy-controllers": "^1.0.1",
"ember-export-application-global": "^1.0.4",
"ember-inflector": "^1.9.4",
"ember-load-initializers": "^0.5.0",
"ember-moment": "6.0.0",
"ember-resolver": "^2.0.3",
"ember-simple-auth": "1.1.0-beta.3",
"event": "^1.0.0",
"events": "^1.1.0",
"express": "^4.13.4",
"glob": "^4.5.3",
"jade": "^1.11.0",
"loader.js": "^4.0.0",
"md-utils": "git+http://gitlab.silvrtree.co.uk/martind2000/md-utils.git",
"morgan": "^1.7.0",
"node-validator": "git+http://gitlab.silvrtree.co.uk/martind2000/node-validator.git",
"oauth2-server": "^2.4.1",
"pg-promise": "^3.3.0",
"util": "^0.10.3"
},
"dependencies": {
"bcrypt": "^0.8.5",
"pg": "^4.5.1"
}
}

15
public/crossdomain.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<!-- Read this: www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->
<!-- Most restrictive policy: -->
<site-control permitted-cross-domain-policies="none"/>
<!-- Least restrictive policy: -->
<!--
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" to-ports="*" secure="false"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
-->
</cross-domain-policy>

BIN
public/images/skyview.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# http://www.robotstxt.org
User-agent: *
Disallow:

3
server/.jshintrc Normal file
View File

@ -0,0 +1,3 @@
{
"node": true
}

37
server/index.js Normal file
View File

@ -0,0 +1,37 @@
/*jshint node:true*/
// To use it create some files under `mocks/`
// e.g. `server/mocks/ember-hamsters.js`
//
// Module.exports = function(app) {
// app.get('/ember-hamsters', function(req, res) {
// res.send('hello');
// });
// };
module.exports = function(app) {
var globSync = require('glob').sync;
var mocks = globSync('./mocks/**/*.js', { cwd: __dirname }).map(require);
var proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map(require);
// Log proxy requests
var morgan = require('morgan');
app.use(morgan('dev'));
function usingProxy() {
return !!process.argv.filter(function(arg) {
return arg.indexOf('--proxy') === 0;
}).length;
}
/* ... */
if (usingProxy()) { return; }
mocks.forEach(function(route) { route(app); });
proxies.forEach(function(route) { route(app); });
};

35
server/mocks/accounts.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbAccounts = require('../units/db-accounts')(db);
module.exports = function(app) {
var express = require('express');
var accountsRouter = express.Router();
accountsRouter.get('/:uid', function(req, res) {
if (/Bearer .+/.test(req.headers.authorization)) {
dbAccounts.sqlGetAccountDetails(req.params.uid)
.then(function(data) {
'use strict';
const response = {
data: {
type: 'accounts', id: data.uid, attributes: {
uid: data.uid, login: data.email, forename: data.forename,
surname: data.surname, memberof: data.member_of
}
}
};
console.log(response);
res.status(200).send(response);
})
.catch(function(err) {
console.error(err);
res.status(401).end();
});
}
});
app.use('/accounts', accountsRouter);
};

86
server/mocks/companies.js Normal file
View File

@ -0,0 +1,86 @@
/*jshint node:true*/
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbCompany = require('../units/db-company')(db);
var $U = require('md-utils');
module.exports = function(app) {
var express = require('express');
var companiesRouter = express.Router();
companiesRouter.get('/:id', function(req, res) {
var id = req.params.id;
dbCompany.sqlGetSimpleCompany(id)
.then(function(data) {
const response = {
data: {
type: 'company', id: id, attributes: $U.reDashObject(data)
}
};
console.log(response);
res.status(200).send(response);
})
.catch(function(err) {
console.error(err);
res.status(401).end();
});
});
companiesRouter.post('/', function(req, res) {
res.status(201).end();
});
companiesRouter.get('/:id', function(req, res) {
res.send({
companies: {
id: req.params.id
}
});
});
companiesRouter.patch('/:id', function(req, res) {
if (/Bearer .+/.test(req.headers.authorization)) {
console.log('Patching: ' + req.params.id);
console.log(req.body.data);
var updateData = $U.unDashObject(req.body.data.attributes);
dbCompany.addNewCompany(updateData)
.then(function(d) {
let response = {
data: {
type: 'company', id: d.cid, attributes: d
}
};
res.status(200).send(response);
})
.catch(function(e) {
console.error(e);
res.status(401).end();
});
}
});
companiesRouter.delete('/:id', function(req, res) {
res.status(204).end();
});
// The POST and PUT call will not contain a request body
// because the body-parser is not included by default.
// To use req.body, run:
// Npm install --save-dev body-parser
app.use('/api/companies', require('body-parser').json({type: 'application/vnd.api+json'}));
// After installing, you need to `use` the body-parser for
// this mock uncommenting the following line:
//
//App.use('/api/companies', require('body-parser').json());
app.use('/api/companies', companiesRouter);
};

View File

@ -0,0 +1,32 @@
doctype html
html(lang="en")
head
meta(name='viewport', content='width=device-width, initial-scale=1.0')
link(rel='stylesheet', href='http://yui.yahooapis.com/pure/0.6.0/pure-min.css')
link(rel='stylesheet', href='css/obrand.css')
title= title
body
.pure-g
.pure-u-1
h1.textcenter= title
#image.pure-u-1
if image_url
img.centerblock(src=image_url)
#links.pure-u-1.pure-menu
ul.pure-menu-list
if link1_text
li.pure-menu-item
a.pure-menu-link.textcenter(href=link1_url)=link1_text
if link2_text
li.pure-menu-item
a.pure-menu-link.textcenter(href=link2_url)=link2_text
if link3_text
li.pure-menu-item
a.pure-menu-link.textcenter(href=link3_url)=link3_text
if link4_text
li.pure-menu-item
a.pure-menu-link.textcenter(href=link4_url)=link4_text

View File

@ -0,0 +1,83 @@
/*jshint node:true*/
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbCompany = require('../units/db-company')(db);
var dbAccounts = require('../units/db-accounts')(db);
var $U = require('md-utils');
var events = require('events');
// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();
module.exports = function(app) {
var express = require('express');
var newcompaniesRouter = express.Router();
eventEmitter.on('makeMemberOf', (uid, cid) => {
console.log('Make ' + uid + ' a member of ' + cid);
dbAccounts.makeMemberOf(uid, cid)
.catch(function(err) {
console.error(err);
});
});
newcompaniesRouter.get('/', function(req, res) {
res.send({
newcompanies: []
});
});
newcompaniesRouter.post('/', function(req, res) {
var updateData = $U.unDashObject(req.body.data.attributes);
if (/Bearer .+/.test(req.headers.authorization)) {
dbCompany.addNewCompany(updateData)
.then(function(d) {
updateData.cid = d.cid;
let response = {
data: {
type: 'newcompany', id: d.cid, attributes: updateData
}
};
eventEmitter.emit('makeMemberOf', updateData.uid, d.cid);
res.status(200).send(response);
})
.catch(function(e) {
console.error(e);
res.status(401).end();
});
}
});
newcompaniesRouter.get('/:id', function(req, res) {
res.send({
newcompanies: {
id: req.params.id
}
});
});
newcompaniesRouter.put('/:id', function(req, res) {
res.send({
newcompanies: {
id: req.params.id
}
});
});
newcompaniesRouter.delete('/:id', function(req, res) {
res.status(204).end();
});
// The POST and PUT call will not contain a request body
// because the body-parser is not included by default.
// To use req.body, run:
// Npm install --save-dev body-parser
app.use('/api/newcompanies', require('body-parser').json({type: 'application/vnd.api+json'}));
// After installing, you need to `use` the body-parser for
// this mock uncommenting the following line:
app.use('/api/newcompanies', newcompaniesRouter);
};

109
server/mocks/pages.js Normal file
View File

@ -0,0 +1,109 @@
/*jshint node:true*/
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbPages = require('../units/db-pages')(db);
var $U = require('md-utils');
var Events = require('events');
var jade = require('jade');
var fs = require('fs');
var eventHandler = new Events();
var util = require('util');
var templates = {
basic: {path: __dirname + '/jade/type0.jade', compiled: null}
};
var eventRenderPage = (page) => {
console.log('+++ eventRenderPage');
doRenderPage(page)
};
var doRenderPage = (page) => {
console.log('+ doRenderPage');
var compiledhtml, _page = $U.unDashObject(page);
var htmlfile = __dirname + '/static/' + _page.pid + '.html';
if (templates.basic.compiled === null) {
templates.basic.compiled = jade.compileFile(templates.basic.path);
}
compiledhtml = templates.basic.compiled(_page);
fs.writeFileSync(htmlfile, compiledhtml);
console.log('- doRenderPage');
};
eventHandler.on('renderPage', eventRenderPage);
module.exports = function(app) {
var express = require('express');
var pagesRouter = express.Router();
pagesRouter.get('/', function(req, res) {
res.send({
pages: []
});
});
pagesRouter.post('/', function(req, res) {
console.log(util.inspect(req.body.data));
dbPages.addNewPage(req.body.data)
.then(function(data) {
let response = {
data: data
};
eventHandler.emit('renderPage',data.attributes);
console.log('Finalising...');
console.log(response);
res.status(200).send(response);
})
.catch((err)=> {
console.error(err);
res.status(401).end();
});
});
pagesRouter.get('/:id', function(req, res) {
res.send({
pages: {
id: req.params.id
}
});
});
pagesRouter.put('/:id', function(req, res) {
res.send({
pages: {
id: req.params.id
}
});
});
pagesRouter.delete('/:id', function(req, res) {
res.status(204).end();
});
// The POST and PUT call will not contain a request body
// because the body-parser is not included by default.
// To use req.body, run:
// Npm install --save-dev body-parser
app.use('/api/pages', require('body-parser').json({type: 'application/vnd.api+json'}));
// After installing, you need to `use` the body-parser for
// this mock uncommenting the following line:
//
//App.use('/api/pages', require('body-parser').json());
app.use('/api/pages', pagesRouter);
};

113
server/mocks/profiles.js Normal file
View File

@ -0,0 +1,113 @@
/*jshint node:true*/
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbAccounts = require('../units/db-accounts')(db);
module.exports = function(app) {
var express = require('express');
var profilesRouter = express.Router();
var moment = require('moment');
profilesRouter.get('/:uid', function(req, res) {
if (/Bearer .+/.test(req.headers.authorization)) {
dbAccounts.sqlGetProfile(req.params.uid)
.then(function(data) {
let response = {data: {}};
if (data === null) {
// No record yet, return an empty one.
response.data = {
type: 'profile', id: req.params.uid, attributes: {
forename: '', surname: '', gender: 0, dob: '', bio: ''
}};
} else {
response.data = {
type: 'profile', id: data.uid, attributes: {
forename: data.forename,
surname: data.surname,
gender: data.gender,
dob: moment(data.dob).format('YYYY-MM-DD'),
bio: data.bio
}
};
}
res.status(200).send(response);
})
.catch(function(e) {
'use strict';
console.error(e);
res.status(401).end();
});
};
});
profilesRouter.post('/', function(req, res) {
res.status(201).end();
});
profilesRouter.get('/:id', function(req, res) {
res.send({
profiles: {
id: req.params.id
}
});
});
profilesRouter.put('/:id', function(req, res) {
res.send({
profiles: {
id: req.params.id
}
});
});
profilesRouter.patch('/:id', function(req, res) {
var data = req.body.data;
var attr = data.attributes;
var updateData = {
uid: data.id,
forename: attr.forename,
surname: attr.surname,
gender: attr.gender,
dob: attr.dob,
bio: attr.bio
};
dbAccounts.addInsertProfile(updateData)
.then(function() {
let response = {
data: {
type: 'profile', id: req.params.id, attributes: data.attributes
}
};
res.status(200).send(response);
})
.catch(function(err) {
'use strict';
console.error(err);
res.status(401).end();
});
});
profilesRouter.delete('/:id', function(req, res) {
res.status(204).end();
});
// The POST and PUT call will not contain a request body
// because the body-parser is not included by default.
// To use req.body, run:
// Npm install --save-dev body-parser
// After installing, you need to `use` the body-parser for
// this mock uncommenting the following line:
//
//App.use('/api/profiles', require('body-parser').json());
app.use('/api/profiles', require('body-parser').json());
app.use('/api/profiles',
require('body-parser').json({type: 'application/vnd.api+json'}));
app.use('/api/profiles', profilesRouter);
};

View File

@ -0,0 +1,9 @@
.textcenter {
text-align: center !important;
}
.centerblock {
display: block;
margin-left: auto;
margin-right: auto;
}

84
server/mocks/token.js Normal file
View File

@ -0,0 +1,84 @@
/*jshint node:true*/
'use strict';
var db = require('../units/db-connector').dbConnection;
var dbAccounts = require('../units/db-accounts')(db);
module.exports = function(app) {
var express = require('express');
var tokenRouter = express.Router();
tokenRouter.get('/', function(req, res) {
res.send({
token: []
});
});
tokenRouter.post('/', function(req, res) {
if (req.body.hasOwnProperty('grant_type')) {
if (req.body.grant_type === 'password') {
dbAccounts.findAccount({
email: req.body.username,
password: req.body.password
})
.then(function(d) {
let loginObj = {
access_token: 'secret token!',
account_id: d.uid,
username: d.username,
account: d.email
};
// Res.status(200).send('{ "access_token": "secret token!", "account_id": d.id }');
res.status(200).send(loginObj);
})
.catch(function(err) {
res.status(400).send(
'{ "error": "No account could be found with those details" }');
});
} else {
res.status(400).send(
'{ "error": "No account could be found with those details" }');
}
} else {
res.status(400).send(
'{ "error": "No account could be found with those details" }');
}
});
tokenRouter.get('/:id', function(req, res) {
res.send({
token: {
id: req.params.id
}
});
});
tokenRouter.put('/:id', function(req, res) {
res.send({
token: {
id: req.params.id
}
});
});
tokenRouter.delete('/:id', function(req, res) {
res.status(204).end();
});
// The POST and PUT call will not contain a request body
// because the body-parser is not included by default.
// To use req.body, run:
// Npm install --save-dev body-parser
// After installing, you need to `use` the body-parser for
// this mock uncommenting the following line:
//
app.use('/token', require('body-parser').json());
app.use('/token', require('body-parser').text());
app.use('/token', require('body-parser').urlencoded());
app.use('/token', tokenRouter);
};

204
server/units/db-accounts.js Normal file
View File

@ -0,0 +1,204 @@
'use strict';
var mdValidator = require('node-validator');
var mdErrors = require('./md-errors');
var bcrypt = require('bcrypt-as-promised');
var newId = require('uuid-pure').newId;
module.exports = function(db) {
var module = {};
module.connectPGP = function() {
return new Promise(function(resolve, reject) {
db.query('select $1::int as number', [1])
.then((data)=> {
resolve(data);
})
.catch((error)=> {
reject(error);
});
});
};
module.sqlInsertAccount = function(data) {
let _data = data;
_data.uid = newId();
return new Promise(function(resolve, reject) {
db.func('insert_user',
[_data.username, _data.email, _data.hash, _data.uid])
.then(()=> {
return resolve('ok');
})
.catch((err)=> {
return reject(err);
});
});
};
module.sqlGetAccount = function(email) {
return new Promise(function(resolve, reject) {
db.oneOrNone('select * from logins where email=$1;', [email])
.then(function(d) {
return resolve(d);
})
.catch((err)=> {
return reject(err);
});
});
};
module.sqlGetAccountDetails = function(uid) {
return new Promise(function(resolve, reject) {
db.one('select * from getAccountDetails($1);',[uid])
.then(function(d) {
console.log('+ sqlGetAccountDetails');
console.log(d);
return resolve(d);
})
.catch((err)=> {
return reject(err);
});
});
};
module.sqlUpsertProfile = function(data) {
var propArray = [
data.uid,
data.forename,
data.surname,
data.gender,
data.dob,
data.bio
];
return new Promise(function(resolve, reject) {
db.func('upsert_profile', propArray)
.then(()=> {
return resolve(true);
})
.catch((err)=> {
return reject(err);
});
});
};
module.sqlMakeMemberOf = function(cid, uid) {
var propArray = [cid,uid];
return new Promise(function(resolve, reject) {
db.func('makeMemberOf', propArray)
.then(()=> {
return resolve(true);
})
.catch((err)=> {
return reject(err);
});
});
};
module.sqlGetProfile = function(uid) {
return new Promise(function(resolve, reject) {
db.oneOrNone('select * from profile where uid=$1;', [uid])
.then(function(d) {
return resolve(d);
})
.catch((err)=> {
return reject(err);
});
});
};
module.addNewAccount = function(data) {
var self = this;
return new Promise((resolve, reject) => {
let _data = {};
_data.username = data.username.trim();
_data.password = data.password.trim();
_data.email = data.email.trim();
if (Object.keys(data).length === 3) {
if (_data.username.length === 0 || _data.password.length === 0 || _data.email.length === 0) {
return reject(mdErrors.error(1000));
}
if (mdValidator.Email(data.email) === false) {
return reject(mdErrors.error(1001));
} else {
// It should be possible to insert the user now.
bcrypt.hash(data.password,10).then((d) => {
_data.hash = d;
self.sqlInsertAccount(_data)
.then(()=> {
return resolve({reply: 'user added'});
})
.catch((err)=> {
return reject(err);
});
});
}
} else {
// Error - required details missing
return reject(mdErrors.error(1002));
}
});
};
module.findAccount = function(data) {
var _data = data;
return new Promise((resolve, reject) => {
this.sqlGetAccount(_data.email)
.then((row) => {
if (row === null) {
return reject(mdErrors.error(1004));
}
// Check password against hash held in db
// noinspection JSUnresolvedVariable
bcrypt.compare(_data.password, row.password_hash)
.then(function() {
let loginDetails = {
id: row.id,
username: row.username,
email: row.email,
uid: row.uid
};
return resolve(loginDetails);
})
// Failure, reject
.catch(function() {
return reject(mdErrors.error(1004));
});
})
.catch(function(err) {
return reject(err);
});
});
};
module.addInsertProfile = function(data) {
return new Promise((resolve, reject) => {
this.sqlUpsertProfile(data)
.then((d)=> {
return resolve(d);
})
.catch((err)=> {
return reject(err);
});
});
};
//makeMemberOf(cid, uid)
module.makeMemberOf = function(cid, uid) {
return new Promise((resolve, reject) => {
this.sqlMakeMemberOf(cid, uid)
.then((d)=> {
return resolve(d);
})
.catch((err)=> {
return reject(err);
});
});
};
return module;
};

115
server/units/db-company.js Normal file
View File

@ -0,0 +1,115 @@
/**
*
* User: Martin Donnelly
* Date: 2016-03-15
* Time: 14:04
*
*/
'use strict';
var $V = require('node-validator');
var mdErrors = require('./md-errors');
var newId = require('uuid-pure').newId;
var $U = require('md-utils');
module.exports = function(db) {
var module = {};
module.sqlInsertCompany = function(data) {
return new Promise(function(resolve, reject) {
db.proc('upsert_company',data)
.then(()=> {
console.log('+sqlInsertCompany OK');
return resolve('ok');
})
.catch((err)=> {
console.log('+sqlInsertCompany failed');
console.log(err);
return reject(err);
});
});
};
module.sqlGetSimpleCompany = function(id) {
return new Promise(function(resolve, reject) {
//db.oneOrNone('select *, company_name company-name from company where cid=$1;', [id])
db.oneOrNone('select company.* from company where cid=$1;', [id])
.then(function(d) {
console.log(d);
return resolve(d);
})
.catch((err)=> {
console.log(err);
return reject(err);
});
});
};
module.addNewCompany = function(data) {
return new Promise((resolve, reject) => {
let _data;
_data = $U.cloneTrim(data);
_data = $U.sanitiseObj(_data,
{company_name: true, address1: true, address2: true, address3: true,
town: false, county: false, pcontact: true, ocontact: true,mobile: true});
if (_data.hasOwnProperty('company_name') && (_data.company_name.length === 0)) {
return reject(mdErrors.error(1100));
}
if ([
_data.address1, _data.address2, _data.address3
].join('').trim().length === 0) {
return reject(mdErrors.error(1101));
}
if ([_data.town, _data.county].join('').trim().length === 0) {
return reject(mdErrors.error(1102));
}
var pcv = $V.checkPostCode(_data.postcode);
if (pcv === '') {
return reject(mdErrors.error(1103));
} else {
_data.postcode = pcv;
}
_data.pcontact = $V.validatePhone(_data.pcontact);
_data.ocontact = $V.validatePhone(_data.ocontact);
_data.mobile = $V.validatePhone(_data.mobile);
if ([
_data.pcontact, _data.ocontact, _data.mobile
].join('').trim().length === 0) {
return reject(mdErrors.error(1104));
}
if (_data.email.length === 0 || !$V.Email(_data.email)) {
return reject(mdErrors.error(1105));
}
if (typeof _data.cid === 'undefined' || _data.cid === null) {
_data.cid = newId();
}
const sqlData = [_data.cid, _data.company_name, _data.address1, _data.address2,
_data.address3, _data.town, _data.county, _data.postcode, _data.country, _data.pcontact,
_data.ocontact, _data.mobile, _data.email];
this.sqlInsertCompany(sqlData)
.then(function(d) {
console.log('Inserted');
console.log(d);
return resolve({cid: _data.cid});
})
.catch(function(err) {
console.log('Failed to insert');
return reject(err);
});
});
};
return module;
};

View File

@ -0,0 +1,21 @@
'uses strict';
/**
*
* User: Martin Donnelly
* Date: 2016-03-11
* Time: 10:22
*
*/
var pgp = require('pg-promise')();
var cn = {
host: 'localhost',
port: 5432,
database: 'oBrand',
user: 'obrand',
password: 'obrand'
};
exports.dbConnection = pgp(cn);

72
server/units/db-pages.js Normal file
View File

@ -0,0 +1,72 @@
'use strict';
var mdErrors = require('./md-errors');
var newId = require('uuid-pure').newId;
var $U = require('md-utils');
/**
*
* User: Martin Donnelly
* Date: 2016-03-24
* Time: 11:10
*
*/
module.exports = function(db) {
var module = {};
module.sqlInsertPage = function(data) {
return new Promise(function(resolve, reject) {
db.func('upsert_page',data)
.then((d)=> {
console.log(d);
console.log('+sqlInsertPage OK');
return resolve('ok');
})
.catch((err)=> {
console.log('+sqlInsertPage failed');
console.log(err);
return reject(err);
});
});
};
module.addNewPage = function(data) {
return new Promise((resolve, reject) => {
let _data, _jsonData;
console.log(data);
_data = $U.cloneTrim(data.attributes);
if (typeof _data.pid === 'undefined' || _data.pid === null) {
_data.pid = newId();
}
_jsonData = $U.newObjectFrom(_data, ['title','image-url','link1-text','link1-url','link2-text','link2-url','link3-text','link3-url','link4-text','link4-url']);
const sqlData = [_data.cid, _data.vid, _data.pid, _data.content, _data.title, JSON.stringify(_jsonData)];
console.log(sqlData);
this.sqlInsertPage(sqlData)
.then(function(d) {
console.log('Inserted');
console.log(d);
data.attributes = _data;
return resolve(data);
})
.catch(function(err) {
console.log('Failed to insert');
return reject(err);
});
});
};
return module;
};

38
server/units/md-errors.js Normal file
View File

@ -0,0 +1,38 @@
/**
*
* User: Martin Donnelly
* Date: 2016-03-10
* Time: 11:31
*
*/
var logger = require('log4js').getLogger();
var MDERRORS = new function() {
'use strict';
var errors = {
1000: {name: 'Account error', title: 'Signup data missing'},
1001: {name: 'Account error', title: 'Email address is not in the correct format'},
1002: {name: 'Account error', title: 'Required details missing'},
1003: {name: 'Account error', title: 'Email does not exist in login table'},
1004: {name: 'Account error', title: 'Email address or password are incorrect'},
1100: {name: 'Company Error', title: 'Company name is missing'},
1101: {name: 'Company Error', title: 'Address details are missing'},
1102: {name: 'Company Error', title: 'Town/County details are missing'},
1103: {name: 'Company Error', title: 'Postcode is missing / incorrect'},
1104: {name: 'Company Error', title: 'Contact phone number is missing'},
1105: {name: 'Company Error', title: 'Email is missing / invalid'}
};
this.error = function(code) {
var estring = '';
estring = errors[code].name + ': ' + errors[code].title + '\nCode: ' + code + '\n';
logger.error(estring);
return ({code: code, name: errors[code].name, title: errors[code].title, string: estring});
};
}();
module.exports = MDERRORS;

13
testem.js Normal file
View File

@ -0,0 +1,13 @@
/*jshint node:true*/
module.exports = {
"framework": "qunit",
"test_page": "tests/index.html?hidepassed",
"disable_watching": true,
"launch_in_ci": [
"PhantomJS"
],
"launch_in_dev": [
"PhantomJS",
"Chrome"
]
};

53
tests/.jshintrc Normal file
View File

@ -0,0 +1,53 @@
{
"predef": [
"server",
"document",
"window",
"location",
"setTimeout",
"$",
"-Promise",
"define",
"console",
"visit",
"exists",
"fillIn",
"click",
"keyEvent",
"triggerEvent",
"find",
"findWithAssert",
"wait",
"DS",
"andThen",
"currentURL",
"currentPath",
"currentRouteName"
],
"node": false,
"browser": false,
"boss": true,
"curly": true,
"debug": false,
"devel": false,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"esnext": true,
"unused": true
}

View File

@ -0,0 +1,5 @@
import Ember from 'ember';
export default function destroyApp(application) {
Ember.run(application, 'destroy');
}

View File

@ -0,0 +1,23 @@
import { module } from 'qunit';
import startApp from '../helpers/start-app';
import destroyApp from '../helpers/destroy-app';
export default function(name, options = {}) {
module(name, {
beforeEach() {
this.application = startApp();
if (options.beforeEach) {
options.beforeEach.apply(this, arguments);
}
},
afterEach() {
if (options.afterEach) {
options.afterEach.apply(this, arguments);
}
destroyApp(this.application);
}
});
}

Some files were not shown because too many files have changed in this diff Show More