Dan Brown

Added initial settings interface, Fixes #9.

1 +<?php
2 +
3 +namespace Oxbow\Http\Controllers;
4 +
5 +use Illuminate\Http\Request;
6 +
7 +use Oxbow\Http\Requests;
8 +use Oxbow\Http\Controllers\Controller;
9 +use Setting;
10 +
11 +class SettingController extends Controller
12 +{
13 + /**
14 + * Display a listing of the settings.
15 + *
16 + * @return Response
17 + */
18 + public function index()
19 + {
20 + $this->checkPermission('settings-update');
21 + return view('settings/index');
22 + }
23 +
24 +
25 +
26 + /**
27 + * Update the specified settings in storage.
28 + *
29 + * @param Request $request
30 + * @return Response
31 + */
32 + public function update(Request $request)
33 + {
34 + $this->checkPermission('settings-update');
35 + // Cycles through posted settings and update them
36 + foreach($request->all() as $name => $value) {
37 + if(strpos($name, 'setting-') !== 0) continue;
38 + $key = str_replace('setting-', '', trim($name));
39 + Setting::put($key, $value);
40 + }
41 + return redirect('/settings');
42 + }
43 +
44 +}
...@@ -71,6 +71,10 @@ Route::group(['middleware' => 'auth'], function () { ...@@ -71,6 +71,10 @@ Route::group(['middleware' => 'auth'], function () {
71 Route::get('/', 'HomeController@index'); 71 Route::get('/', 'HomeController@index');
72 Route::get('/home', 'HomeController@index'); 72 Route::get('/home', 'HomeController@index');
73 73
74 + // Settings
75 + Route::get('/settings', 'SettingController@index');
76 + Route::post('/settings', 'SettingController@update');
77 +
74 78
75 }); 79 });
76 80
......
...@@ -4,6 +4,7 @@ namespace Oxbow\Providers; ...@@ -4,6 +4,7 @@ namespace Oxbow\Providers;
4 4
5 use Illuminate\Support\ServiceProvider; 5 use Illuminate\Support\ServiceProvider;
6 use Oxbow\Services\ActivityService; 6 use Oxbow\Services\ActivityService;
7 +use Oxbow\Services\SettingService;
7 8
8 class CustomFacadeProvider extends ServiceProvider 9 class CustomFacadeProvider extends ServiceProvider
9 { 10 {
...@@ -27,5 +28,9 @@ class CustomFacadeProvider extends ServiceProvider ...@@ -27,5 +28,9 @@ class CustomFacadeProvider extends ServiceProvider
27 $this->app->bind('activity', function() { 28 $this->app->bind('activity', function() {
28 return new ActivityService($this->app->make('Oxbow\Activity')); 29 return new ActivityService($this->app->make('Oxbow\Activity'));
29 }); 30 });
31 +
32 + $this->app->bind('setting', function() {
33 + return new SettingService($this->app->make('Oxbow\Setting'));
34 + });
30 } 35 }
31 } 36 }
......
...@@ -81,11 +81,13 @@ class ActivityService ...@@ -81,11 +81,13 @@ class ActivityService
81 * Gets the latest activity. 81 * Gets the latest activity.
82 * @param int $count 82 * @param int $count
83 * @param int $page 83 * @param int $page
84 + * @return array
84 */ 85 */
85 public function latest($count = 20, $page = 0) 86 public function latest($count = 20, $page = 0)
86 { 87 {
87 - return $this->activity->orderBy('created_at', 'desc') 88 + $activityList = $this->activity->orderBy('created_at', 'desc')
88 ->skip($count * $page)->take($count)->get(); 89 ->skip($count * $page)->take($count)->get();
90 + return $this->filterSimilar($activityList);
89 } 91 }
90 92
91 /** 93 /**
...@@ -99,7 +101,7 @@ class ActivityService ...@@ -99,7 +101,7 @@ class ActivityService
99 function entityActivity($entity, $count = 20, $page = 0) 101 function entityActivity($entity, $count = 20, $page = 0)
100 { 102 {
101 $activity = $entity->hasMany('Oxbow\Activity')->orderBy('created_at', 'desc') 103 $activity = $entity->hasMany('Oxbow\Activity')->orderBy('created_at', 'desc')
102 - ->skip($count*$page)->take($count)->get(); 104 + ->skip($count * $page)->take($count)->get();
103 105
104 return $this->filterSimilar($activity); 106 return $this->filterSimilar($activity);
105 } 107 }
...@@ -109,16 +111,17 @@ class ActivityService ...@@ -109,16 +111,17 @@ class ActivityService
109 * @param Activity[] $activity 111 * @param Activity[] $activity
110 * @return array 112 * @return array
111 */ 113 */
112 - protected function filterSimilar($activity) { 114 + protected function filterSimilar($activity)
115 + {
113 $newActivity = []; 116 $newActivity = [];
114 $previousItem = false; 117 $previousItem = false;
115 - foreach($activity as $activityItem) { 118 + foreach ($activity as $activityItem) {
116 - if($previousItem === false) { 119 + if ($previousItem === false) {
117 $previousItem = $activityItem; 120 $previousItem = $activityItem;
118 $newActivity[] = $activityItem; 121 $newActivity[] = $activityItem;
119 continue; 122 continue;
120 } 123 }
121 - if(!$activityItem->isSimilarTo($previousItem)) { 124 + if (!$activityItem->isSimilarTo($previousItem)) {
122 $newActivity[] = $activityItem; 125 $newActivity[] = $activityItem;
123 } 126 }
124 $previousItem = $activityItem; 127 $previousItem = $activityItem;
......
1 +<?php namespace Oxbow\Services\Facades;
2 +
3 +
4 +use Illuminate\Support\Facades\Facade;
5 +
6 +class Setting extends Facade
7 +{
8 + /**
9 + * Get the registered name of the component.
10 + *
11 + * @return string
12 + */
13 + protected static function getFacadeAccessor() { return 'setting'; }
14 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<?php namespace Oxbow\Services;
2 +
3 +use Oxbow\Setting;
4 +
5 +/**
6 + * Class SettingService
7 + *
8 + * The settings are a simple key-value database store.
9 + *
10 + * @package Oxbow\Services
11 + */
12 +class SettingService
13 +{
14 +
15 + protected $setting;
16 +
17 + /**
18 + * SettingService constructor.
19 + * @param $setting
20 + */
21 + public function __construct(Setting $setting)
22 + {
23 + $this->setting = $setting;
24 + }
25 +
26 + /**
27 + * Gets a setting from the database,
28 + * If not found, Returns default, Which is false by default.
29 + * @param $key
30 + * @param string|bool $default
31 + * @return bool|string
32 + */
33 + public function get($key, $default = false)
34 + {
35 + $setting = $this->getSettingObjectByKey($key);
36 + return $setting === null ? $default : $setting->value;
37 + }
38 +
39 + /**
40 + * Checks if a setting exists.
41 + * @param $key
42 + * @return bool
43 + */
44 + public function has($key)
45 + {
46 + $setting = $this->getSettingObjectByKey($key);
47 + return $setting !== null;
48 + }
49 +
50 + /**
51 + * Add a setting to the database.
52 + * @param $key
53 + * @param $value
54 + * @return bool
55 + */
56 + public function put($key, $value)
57 + {
58 + $setting = $this->setting->firstOrNew([
59 + 'setting_key' => $key
60 + ]);
61 + $setting->value = $value;
62 + $setting->save();
63 + return true;
64 + }
65 +
66 + /**
67 + * Removes a setting from the database.
68 + * @param $key
69 + * @return bool
70 + */
71 + public function remove($key)
72 + {
73 + $setting = $this->getSettingObjectByKey($key);
74 + if($setting) {
75 + $setting->delete();
76 + }
77 + return true;
78 + }
79 +
80 + /**
81 + * Gets a setting model from the database for the given key.
82 + * @param $key
83 + * @return mixed
84 + */
85 + private function getSettingObjectByKey($key) {
86 + return $this->setting->where('setting_key', '=', $key)->first();
87 + }
88 +
89 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<?php
2 +
3 +namespace Oxbow;
4 +
5 +use Illuminate\Database\Eloquent\Model;
6 +
7 +class Setting extends Model
8 +{
9 + protected $fillable = ['setting_key', 'value'];
10 +
11 + protected $primaryKey = 'setting_key';
12 +}
...@@ -211,6 +211,7 @@ return [ ...@@ -211,6 +211,7 @@ return [
211 */ 211 */
212 212
213 'Activity' => Oxbow\Services\Facades\Activity::class, 213 'Activity' => Oxbow\Services\Facades\Activity::class,
214 + 'Setting' => Oxbow\Services\Facades\Setting::class,
214 215
215 ], 216 ],
216 217
......
1 +<?php
2 +
3 +use Illuminate\Database\Schema\Blueprint;
4 +use Illuminate\Database\Migrations\Migration;
5 +
6 +class CreateSettingsTable extends Migration
7 +{
8 + /**
9 + * Run the migrations.
10 + *
11 + * @return void
12 + */
13 + public function up()
14 + {
15 + Schema::create('settings', function (Blueprint $table) {
16 + $table->string('setting_key')->primary()->indexed();
17 + $table->text('value');
18 + $table->timestamps();
19 + });
20 + }
21 +
22 + /**
23 + * Reverse the migrations.
24 + *
25 + * @return void
26 + */
27 + public function down()
28 + {
29 + Schema::drop('settings');
30 + }
31 +}
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
10 color: #222; 10 color: #222;
11 width: 250px; 11 width: 250px;
12 max-width: 100%; 12 max-width: 100%;
13 - -webkit-appearance:none; 13 + //-webkit-appearance:none;
14 &.neg, &.invalid { 14 &.neg, &.invalid {
15 border: 1px solid $negative; 15 border: 1px solid $negative;
16 } 16 }
...@@ -25,9 +25,10 @@ ...@@ -25,9 +25,10 @@
25 label { 25 label {
26 display: block; 26 display: block;
27 line-height: 1.4em; 27 line-height: 1.4em;
28 - font-size: 0.9em; 28 + font-size: 0.94em;
29 font-weight: 500; 29 font-weight: 500;
30 - color: #333; 30 + color: #666;
31 + padding-bottom: 2px;
31 } 32 }
32 33
33 label.radio, label.checkbox { 34 label.radio, label.checkbox {
......
...@@ -486,3 +486,18 @@ body.dragging, body.dragging * { ...@@ -486,3 +486,18 @@ body.dragging, body.dragging * {
486 color: #EEE; 486 color: #EEE;
487 } 487 }
488 } 488 }
489 +
490 +.setting-nav {
491 + margin-top: $-l;
492 + border-top: 1px solid #DDD;
493 + border-bottom: 1px solid #DDD;
494 + a {
495 + padding: $-m;
496 + display: inline-block;
497 + //color: #666;
498 + &.selected {
499 + //color: $primary;
500 + background-color: #f8f8f8;
501 + }
502 + }
503 +}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
54 <header> 54 <header>
55 <div class="padded row clearfix"> 55 <div class="padded row clearfix">
56 <div class="col-md-12 logo-container"> 56 <div class="col-md-12 logo-container">
57 - <a href="/" class="logo">BookStack</a> 57 + <a href="/" class="logo">{{ Setting::get('app-name', 'BookStack') }}</a>
58 <div class="user-overview"> 58 <div class="user-overview">
59 <img class="avatar" src="{{Auth::user()->getAvatar(50)}}" alt="{{ Auth::user()->name }}"> 59 <img class="avatar" src="{{Auth::user()->getAvatar(50)}}" alt="{{ Auth::user()->name }}">
60 <span class="user-name"> 60 <span class="user-name">
......
...@@ -78,8 +78,6 @@ ...@@ -78,8 +78,6 @@
78 </div> 78 </div>
79 79
80 80
81 -
82 -
83 <script> 81 <script>
84 $(function() { 82 $(function() {
85 83
......
1 +@extends('base')
2 +
3 +@section('content')
4 +
5 + @include('settings/navbar', ['selected' => 'settings'])
6 +
7 + <div class="page-content">
8 + <h1>Settings</h1>
9 +
10 + <form action="/settings" method="POST">
11 + {!! csrf_field() !!}
12 + <div class="form-group">
13 + <label for="setting-app-name">Application Name</label>
14 + <input type="text" value="{{ Setting::get('app-name') }}" name="setting-app-name" id="setting-app-name">
15 + </div>
16 + <div class="form-group">
17 + <button type="submit" class="button pos">Update Settings</button>
18 + </div>
19 + </form>
20 +
21 + </div>
22 +
23 +@stop
...\ No newline at end of file ...\ No newline at end of file
1 +<div class="row">
2 + <div class="col-md-6 col-md-offset-3 setting-nav">
3 + <a href="/settings" @if($selected == 'settings') class="selected" @endif><i class="zmdi zmdi-settings"></i>Settings</a>
4 + <a href="/users" @if($selected == 'users') class="selected" @endif><i class="zmdi zmdi-accounts"></i>Users</a>
5 + </div>
6 +</div>
...\ No newline at end of file ...\ No newline at end of file
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 17
18 <div class="row"> 18 <div class="row">
19 <div class="col-md-6"> 19 <div class="col-md-6">
20 - <h1>Edit User</h1> 20 + <h1>Edit {{ $user->id === $currentUser->id ? 'Profile' : 'User' }}</h1>
21 <form action="/users/{{$user->id}}" method="post"> 21 <form action="/users/{{$user->id}}" method="post">
22 {!! csrf_field() !!} 22 {!! csrf_field() !!}
23 <input type="hidden" name="_method" value="put"> 23 <input type="hidden" name="_method" value="put">
......
...@@ -3,21 +3,15 @@ ...@@ -3,21 +3,15 @@
3 3
4 @section('content') 4 @section('content')
5 5
6 - 6 + @include('settings/navbar', ['selected' => 'users'])
7 - <div class="row faded-small">
8 - <div class="col-md-6"></div>
9 - <div class="col-md-6 faded">
10 - <div class="action-buttons">
11 - @if($currentUser->can('user-create'))
12 - <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>New User</a>
13 - @endif
14 - </div>
15 - </div>
16 - </div>
17 -
18 7
19 <div class="page-content"> 8 <div class="page-content">
20 <h1>Users</h1> 9 <h1>Users</h1>
10 + @if($currentUser->can('user-create'))
11 + <p>
12 + <a href="/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>Add New User</a>
13 + </p>
14 + @endif
21 <table class="table"> 15 <table class="table">
22 <tr> 16 <tr>
23 <th></th> 17 <th></th>
......