Skip to content

Commit 68cf2fb

Browse files
author
dularion
committed
Application now ignores settings for storage & API-Key in config.groovy. These values can now be adjusted in the user-interface. If the values are empty at first, the user gehts redirected to the settings page when trying to access the dashboard.
1 parent 3cdf99b commit 68cf2fb

21 files changed

+350
-113
lines changed

grails-app/assets/javascripts/application.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
//
33
// Any JavaScript file within this directory can be referenced here using a relative path.
44
//
5-
// You're free to add application-wide JavaScript to this file, but it's generally better
5+
// You're free to add application-wide JavaScript to this file, but it's generally better
66
// to create separate JavaScript files as needed.
77
//
8-
//= require jquery
98
//= require spring-websocket
9+
//= require jquery/dist/jquery.js
1010
//= require angular/angular.js
1111
//= require angular-ui-router/release/angular-ui-router.js
1212
//= require angular-sanitize/angular-sanitize.js
@@ -18,6 +18,7 @@
1818
//= require jquery-ui-1.11.4.custom/jquery-ui.js
1919
//= require angular-ui-slider/src/slider.js
2020
//= require mousetrap/mousetrap.js
21+
//= require Autolinker.js/dist/Autolinker.js
2122
//= require streama-app.js
2223
//= require_tree .
23-
//= require_self
24+
//= require_self
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
streamaApp.controller('adminSettingsCtrl', ['$scope', 'apiService', '$sce', function ($scope, apiService, $sce) {
4+
5+
$scope.loading = true;
6+
7+
apiService.settings.list().success(function (data) {
8+
$scope.settings = data;
9+
10+
_.forEach(data, function (setting) {
11+
setting.description = $sce.trustAsHtml(Autolinker.link(setting.description, { newWindow: "true" } ));
12+
});
13+
$scope.loading = false;
14+
});
15+
16+
$scope.updateMultipleSettings = function (settings) {
17+
settings.invalid = false;
18+
19+
apiService.settings.updateMultiple(settings)
20+
.success(function () {
21+
window.location.reload();
22+
})
23+
.error(function () {
24+
alertify.error('There was an error saving your settings. Please refer to the server-log.');
25+
});
26+
};
27+
28+
29+
$scope.validateSettings = function (settings) {
30+
$scope.changeValue(settings);
31+
$scope.loading = true;
32+
33+
apiService.settings.validateSettings(settings)
34+
.success(function (data) {
35+
alertify.success(data.message);
36+
settings.valid = true;
37+
$scope.loading = false;
38+
})
39+
.error(function (data) {
40+
alertify.error(data.message);
41+
settings.invalid = true;
42+
$scope.loading = false;
43+
});
44+
};
45+
46+
$scope.changeValue = function (settings) {
47+
settings.valid = undefined;
48+
settings.invalid = undefined;
49+
settings.dirty = settings.value;
50+
};
51+
52+
53+
$scope.anySettingsInvalid = function () {
54+
return _.find($scope.settings, function (setting) {
55+
return setting.invalid || (setting.dirty && !setting.valid) || !setting.value;
56+
});
57+
};
58+
59+
}]);
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
'use strict';
22

3-
streamaApp.controller('dashCtrl', ['$scope', 'apiService', function ($scope, apiService) {
3+
streamaApp.controller('dashCtrl', ['$scope', 'apiService', '$state', function ($scope, apiService, $state) {
44
$scope.loading = true;
5-
6-
apiService.video.dash()
7-
.success(function (data) {
8-
$scope.episodes = data.firstEpisodes;
9-
$scope.continueWatching = data.continueWatching;
10-
$scope.movies = data.movies;
11-
$scope.loading = false;
12-
})
13-
.error(function () {
14-
alertify('A server error occured.');
15-
$scope.loading = false;
16-
});
175

18-
}]);
6+
apiService.settings.list().success(function (data) {
7+
var TheMovieDbAPI = _.find(data, {settingsKey: 'TheMovieDB API key'});
8+
9+
if(!TheMovieDbAPI.value){
10+
alertify.alert('You need to fill out some required base-settings. You will be redirected to the settings page now.', function () {
11+
$state.go('admin.settings');
12+
});
13+
}else{
14+
apiService.video.dash()
15+
.success(function (data) {
16+
$scope.episodes = data.firstEpisodes;
17+
$scope.continueWatching = data.continueWatching;
18+
$scope.movies = data.movies;
19+
$scope.loading = false;
20+
})
21+
.error(function () {
22+
alertify('A server error occured.');
23+
$scope.loading = false;
24+
});
25+
}
26+
});
27+
28+
}]);

grails-app/assets/javascripts/services/api-service.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ streamaApp.factory('apiService', ['$http', function ($http) {
77
currentUser: function () {
88
return $http.get(urlBase + 'user/current.json');
99
},
10-
11-
10+
11+
1212
tvShow: {
1313
get: function (id) {
1414
return $http.get(urlBase + 'tvShow/show.json', {params: {id: id}});
@@ -89,7 +89,7 @@ streamaApp.factory('apiService', ['$http', function ($http) {
8989
return $http.get(urlBase + 'episode.json', {params: params});
9090
}
9191
},
92-
92+
9393
movie: {
9494
get: function (id) {
9595
return $http.get(urlBase + 'movie/show.json', {params: {id: id}});
@@ -115,6 +115,19 @@ streamaApp.factory('apiService', ['$http', function ($http) {
115115
},
116116

117117

118+
settings: {
119+
list: function () {
120+
return $http.get(urlBase + 'settings.json');
121+
},
122+
updateMultiple: function (data) {
123+
return $http.post(urlBase + 'settings/updateMultiple.json', data);
124+
},
125+
validateSettings: function (data) {
126+
return $http.post(urlBase + 'settings/validateSettings.json', data);
127+
}
128+
},
129+
130+
118131
theMovieDb: {
119132
search: function (type, name) {
120133
return $http.get(urlBase + 'theMovieDb/search.json', {params: {type: type, name: name}});
@@ -123,11 +136,11 @@ streamaApp.factory('apiService', ['$http', function ($http) {
123136
return $http.get(urlBase + 'theMovieDb/seasonForShow.json', {params: params});
124137
}
125138
},
126-
139+
127140
websocket: {
128141
triggerPlayerAction: function (params) {
129142
return $http.get(urlBase + 'websocket/triggerPlayerAction.json', {params: params});
130143
}
131144
}
132145
};
133-
}]);
146+
}]);

grails-app/assets/javascripts/services/upload-service.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ streamaApp.factory('uploadService', ['$http', 'Upload', '$location', function ($
2121
uploadStatus.percentage = progressPercentage;
2222
})
2323

24-
.success(callback || angular.noop);
24+
.success(callback || angular.noop)
25+
.error(function (err) {
26+
console.log('%c err', 'color: deeppink; font-weight: bold; text-shadow: 0 0 5px deeppink;', arguments);
27+
alertify.error(err)
28+
});
2529

2630
}
2731
}
2832
}
2933
};
30-
}]);
34+
}]);

grails-app/assets/javascripts/streama-app.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ streamaApp.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', func
3939
templateUrl: 'admin-users.htm',
4040
controller: 'adminUsersCtrl'
4141
})
42+
.state('admin.settings', {
43+
url: '/settings',
44+
templateUrl: 'admin-settings.htm',
45+
controller: 'adminSettingsCtrl'
46+
})
4247
.state('admin.shows', {
4348
url: '/shows',
4449
templateUrl: 'admin-shows.htm',
@@ -70,6 +75,11 @@ streamaApp.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', func
7075
return response || $q.when(response);
7176
},
7277
responseError: function (response) {
78+
79+
if(response.status != 404){
80+
alertify.error('A system error occurred');
81+
}
82+
7383
return $q.reject(response);
7484
}
7585
};
@@ -80,4 +90,4 @@ streamaApp.run(['$rootScope', '$state', function ($rootScope, $state) {
8090
$rootScope.isCurrentState = function (stateName) {
8191
return ($state.current.name == stateName);
8292
};
83-
}]);
93+
}]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<h1>
2+
Settings
3+
4+
<div class="spinner" ng-show="loading">
5+
<div class="bounce1"></div>
6+
<div class="bounce2"></div>
7+
<div class="bounce3"></div>
8+
</div>
9+
</h1>
10+
11+
12+
13+
<hr/>
14+
15+
<form name="settings-form" class="settings-form">
16+
<div class="form-group row-slim" ng-repeat="setting in settings">
17+
<div class="col-sm-3">
18+
<label class="control-label">{{setting.settingsKey}}</label>
19+
</div>
20+
<div class="col-sm-7" ng-class="{'has-error has-feedback': setting.invalid, 'has-success has-feedback': setting.valid}">
21+
<input required type="text" class="form-control" ng-model="setting.value" placeholder="{{setting.settingsKey}}" ng-change="changeValue(setting)">
22+
23+
<span class="glyphicon ion-close form-control-feedback" ng-show="setting.invalid" aria-hidden="true"></span>
24+
<span class="glyphicon ion-checkmark form-control-feedback" ng-show="setting.valid" aria-hidden="true"></span>
25+
26+
</div>
27+
<div class="col-sm-2">
28+
<button type="button" class="btn btn-success btn-block" ng-click="validateSettings(setting)" ng-show="!setting.valid && setting.dirty">validate</button>
29+
</div>
30+
<div class="col-sm-7 col-sm-offset-3">
31+
<p class="settings-description" ng-bind-html="setting.description"></p>
32+
</div>
33+
</div>
34+
</form>
35+
36+
37+
<hr/>
38+
39+
<button class="btn btn-primary" ng-click="updateMultipleSettings(settings)" ng-disabled="anySettingsInvalid()">Save Settings</button>
40+

grails-app/assets/javascripts/streama-app/templates/admin.tpl.htm

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
<li ng-class="{'active': isCurrentState('admin.users')}">
1111
<a ui-sref="admin.users">Users</a>
1212
</li>
13+
<li ng-class="{'active': isCurrentState('admin.settings')}">
14+
<a ui-sref="admin.settings">Settings</a>
15+
</li>
1316
</ul>
1417
</div>
15-
18+
1619
<div class="admin-content">
1720
<ui-view/>
1821
</div>
19-
</div>
22+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.settings-form{
2+
@include clearfix;
3+
4+
.settings-description{
5+
margin-top: 7px;
6+
opacity: 0.8;
7+
margin-bottom: 30px;
8+
}
9+
}

grails-app/assets/stylesheets/style.css

+9
Original file line numberDiff line numberDiff line change
@@ -4245,3 +4245,12 @@ body.mdx-active #mdx-control-view {
42454245
.modal-dialog .modal-footer {
42464246
border-color: rgba(255, 255, 255, 0.25);
42474247
padding: 9px 14px; }
4248+
4249+
.settings-form:after {
4250+
content: "";
4251+
display: table;
4252+
clear: both; }
4253+
.settings-form .settings-description {
4254+
margin-top: 7px;
4255+
opacity: 0.8;
4256+
margin-bottom: 30px; }

grails-app/assets/stylesheets/style.scss

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
@import "player-controls";
1616
@import "invite";
1717
@import "modal";
18+
@import "settings";

grails-app/conf/BootStrap.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
class BootStrap {
2-
2+
33
def marshallerService
44
def defaultDataService
55

66
def init = { servletContext ->
77
marshallerService.init()
88
defaultDataService.createDefaultRoles()
99
defaultDataService.createDefaultUsers()
10+
defaultDataService.createDefaultSettings()
1011
}
1112
def destroy = {
1213
}

grails-app/conf/Config.groovy

+2-8
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,6 @@ log4j.main = {
150150
}
151151

152152

153-
streama {
154-
storage {
155-
path = "/data/streama"
156-
}
157-
themoviedbAPI = "e1584c7cc0072947d4776de6df7b8822"
158-
}
159153

160154
grails.databinding.dateFormats = [
161155
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", // javascript format in json
@@ -167,13 +161,12 @@ grails.databinding.dateFormats = [
167161
grails.plugin.springsecurity.userLookup.userDomainClassName = 'streama.User'
168162
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'streama.UserRole'
169163
grails.plugin.springsecurity.authority.className = 'streama.Role'
170-
grails.plugin.springsecurity.successHandler.defaultTargetUrl = '/user/loginTarget'
171164

172165
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
173166
'/': ['IS_AUTHENTICATED_REMEMBERED'],
174167
'/index': ['IS_AUTHENTICATED_REMEMBERED'],
175168
'/index.gsp': ['IS_AUTHENTICATED_REMEMBERED'],
176-
169+
177170
'/tvShow/**': ['IS_AUTHENTICATED_REMEMBERED'],
178171
'/video/**': ['IS_AUTHENTICATED_REMEMBERED'],
179172
'/viewingStatus/**': ['IS_AUTHENTICATED_REMEMBERED'],
@@ -186,6 +179,7 @@ grails.plugin.springsecurity.controllerAnnotations.staticRules = [
186179
'/appSettings/**': ['IS_AUTHENTICATED_REMEMBERED'],
187180
'/stomp/**': ['IS_AUTHENTICATED_REMEMBERED'],
188181
'/websocket/**': ['IS_AUTHENTICATED_REMEMBERED'],
182+
'/settings/**': ['IS_AUTHENTICATED_REMEMBERED'],
189183

190184
'/invite/**': ['permitAll'],
191185
'/assets/**': ['permitAll'],

grails-app/conf/UrlMappings.groovy

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class UrlMappings {
88
}
99

1010
"/"(view:"/index")
11+
"/setSettings"(view:'/setSettings')
12+
1113
"500"(view:'/error')
1214
}
1315
}

0 commit comments

Comments
 (0)