diff --git a/app/Household.php b/app/Household.php index f4698004..737ee5db 100644 --- a/app/Household.php +++ b/app/Household.php @@ -79,6 +79,11 @@ protected static function boot() } } + public function scopeDraft ($query) + { + return $query->where('draft', '=', 'Y'); + } + public function child() { return $this->hasMany("\App\Child"); } diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php index 130ba80a..6e48a63f 100644 --- a/app/Http/Controllers/Admin/DashboardController.php +++ b/app/Http/Controllers/Admin/DashboardController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers\Admin; use App\Base\Controllers\AdminController; +use App\Household; +use App\User; use Carbon\Carbon; use Illuminate\Support\Collection; use LaravelAnalytics; @@ -56,256 +58,11 @@ public function __construct() public function getIndex() { - /* - $statistics = [ - 'keywords' => LaravelAnalytics::getTopKeywords($this->period, $this->limit), - 'referrers' => LaravelAnalytics::getTopReferrers($this->period, $this->limit), - 'browsers' => LaravelAnalytics::getTopBrowsers($this->period, $this->limit), - 'pages' => LaravelAnalytics::getMostVisitedPages($this->period, $this->limit), - 'users' => LaravelAnalytics::getActiveUsers(), - 'total_visits' => $this->getTotalVisits(), - 'landings' => $this->getLandings(), - 'exits' => $this->getExits(), - 'times' => $this->getTimeOnPages(), - 'sources' => $this->getSources(), - 'ops' => $this->getOperatingSystems(), - 'browsers' => $this->getBrowsers(), - 'countries' => $this->getCountries(), - 'visits' => $this->getDailyVisits(), - 'regions' => $this->getRegions(), - 'averages' => $this->getAverages() - ]; - */ - $statistics = array(); - return view('admin.dashboard.index', compact('statistics')); - } - - /** - * Simplify the query - * - * @param array $options - * @param string $metrics - * @return mixed - */ - private function query($options = [], $metrics = 'ga:visits') - { - return LaravelAnalytics::performQuery($this->start, $this->end, $metrics, $options)->rows; - } - - /** - * Transform analytics array into a collection - * - * @param $data - * @param $fields - * @param int $offset - * @return Collection - */ - private function makeCollection($data, $fields, $offset = 1) - { - if (is_null($data)) { - return new Collection([]); - } else { - foreach ($data as $pageRow) { - $keywordData[] = [$fields[0] => $pageRow[0], $fields[1] => $pageRow[$offset]]; - } - return new Collection($keywordData); - } - } - - /** - * Total visits - * - * @return mixed - */ - private function getTotalVisits() - { - $options = [ - 'dimensions' => 'ga:year', - ]; - return $this->query($options)[0][1]; - } - - /** - * Landing pages - * - * @return mixed - */ - private function getLandings() - { - $options = [ - 'dimensions' => 'ga:landingPagePath', - 'sort' => '-ga:entrances', - 'max-results' => $this->limit - ]; - $data = $this->query($options, 'ga:entrances'); - return $this->makeCollection($data, ['0' => 'path', '1' => 'visits']); - } - - /** - * Exit pages - * - * @return mixed - */ - private function getExits() - { - $options = [ - 'dimensions' => 'ga:exitPagePath', - 'sort' => '-ga:exits', - 'max-results' => $this->limit - ]; - $data = $this->query($options, 'ga:exits'); - return $this->makeCollection($data, ['0' => 'path', '1' => 'visits']); - } - - /** - * Time spent on pages - * - * @return Collection - */ - public function getTimeOnPages() - { - $options = [ - 'dimensions' => 'ga:pagePath', - 'sort' => '-ga:timeOnPage', - 'max-results' => $this->limit - ]; - $data = $this->query($options, 'ga:timeOnPage'); - return $this->makeCollection($data, ['0' => 'path', '1' => 'time']); - } - - /** - * Traffic sources - * - * @return mixed - */ - private function getSources() - { - $options = [ - 'dimensions' => 'ga:source, ga:medium', - 'sort' => '-ga:visits', - 'max-results' => $this->limit - ]; - $data = $this->query($options); - return $this->makeCollection($data, ['0' => 'path', '1' => 'visits'], 2); - } - - /** - * Operating systems - * - * @return mixed - */ - public function getOperatingSystems() - { - $options = [ - 'dimensions' => 'ga:operatingSystem', - 'sort' => '-ga:visits', - 'max-results' => $this->limit - ]; - $data = $this->query($options); - return $this->makeCollection($data, ['0' => 'os', '1' => 'visits']); - } - - /** - * Browsers - * - * @return mixed - */ - public function getBrowsers() - { - $options = [ - 'dimensions' => 'ga:browser', - 'sort' => '-ga:visits', - 'max-results' => $this->limit - ]; - $data = $this->query($options); - return $this->makeCollection($data, ['0' => 'browser', '1' => 'visits']); - } - - /** - * Country distribution - * - * @return string - */ - private function getCountries() - { - $options = [ - 'dimensions' => 'ga:country', - 'sort' => '-ga:visits' - ]; - $array = $this->query($options); - $visits = []; - if (count($array)) { - foreach ($array as $k => $v) { - $visits[$k] = [$v[0], (int) $v[1]]; - } - } - return json_encode($visits); - } - - /** - * Daily visits - * - * @return string - */ - private function getDailyVisits() - { - $options = [ - 'dimensions' => 'ga:date' - ]; - $array = $this->query($options); - $visits = []; - foreach ($array as $k => $v) { - $visits[$k]['date'] = Carbon::parse($v['0'])->format('Y-m-d'); - $visits[$k]['visits'] = $v['1']; - } - return json_encode($visits); - } - - /** - * Region distribution for a specific country - * - * @return string - */ - private function getRegions() - { - $options = [ - 'dimensions' => 'ga:country, ga:region', - 'sort' => '-ga:visits', - 'filters' => 'ga:country==' . $this->country . '' - ]; - $array = $this->query($options); - $visits = []; - if (count($array)) { - foreach ($array as $k => $v) { - $visits[$k] = [str_replace(" Province", "", $v[1]), (int) $v[2]]; - } - } - return json_encode($visits); - } - - /** - * Average time on pages, bounce rate and page views per visits - * - * @return array - */ - private function getAverages() - { - $options = [ - 'dimensions' => 'ga:pagePath' - ]; - $array = $this->query($options, 'ga:avgTimeOnPage, ga:entranceBounceRate, ga:pageviewsPerVisit'); - $count = count($array); - $average = ['time' => 0, 'bounce' => 0, 'visit' => 0]; - if (count($array)) { - foreach ($array as $v) { - $average['time'] += $v['1']; - $average['bounce'] += $v['2']; - $average['visit'] += $v['3']; - } - $average['time'] = ($average['time'] ? floor($average['time'] / $count) : 0); - $average['bounce'] = ($average['bounce'] ? round($average['bounce'] / $count, 2) : 0); - $average['visit'] = ($average['visit'] ? round($average['visit'] / $count, 2) : 0); - } - return $average; + $accounts_pending_approval = User::query()->pending()->count(); + $draftCount = Household::query()->draft()->count(); + return view('admin.dashboard.index', [ + 'accounts_pending_approval' => $accounts_pending_approval, + 'drafts' => $draftCount + ]); } } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 8c0ec357..c59393ee 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -14,7 +14,13 @@ class UserController extends AdminController { - /** + public function __construct() + { + $this->middleware('admins_only'); + parent::__construct(); + } + + /** * Display a listing of the users. * @return Response */ @@ -169,8 +175,7 @@ public function searchPending(Request $request) ->select ("users.*", "affiliation.type", "affiliation.name") ->join ("affiliation", "affiliation.id", "=", "users.affiliation_id") ->where ("name_last", "LIKE", "$search%") - ->where ("confirmed_email", "=", "Y") - ->where("approved", "=", "N") + ->pending() ->orderBy ($columns[$order[0]["column"]]["name"], $order[0]["dir"]); $count = $users->count (); diff --git a/app/Http/Controllers/Api/HouseholdController.php b/app/Http/Controllers/Api/HouseholdController.php index f44ca54a..cc91265b 100644 --- a/app/Http/Controllers/Api/HouseholdController.php +++ b/app/Http/Controllers/Api/HouseholdController.php @@ -117,8 +117,8 @@ public function upload_attachment(Request $request) { public function sendNotification($id) { Mail::queue("email.nomination_submitted", [ "id" => $id], function($message) use($id) { $message->from(env("MAIL_FROM_ADDRESS")); - $message->to(env("NOMINATION_NOTICE_ADDRESS")); - $message->subject(env("NOMINATION_SUBJECT")); + $message->to(env("MAIL_ADMIN_ADDRESS")); + $message->subject("New nomination submitted"); }); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 842c6302..53eead07 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -59,6 +59,7 @@ class Kernel extends HttpKernel 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'admins_only' => \App\Http\Middleware\Custom\AdminsOnly::class ]; } diff --git a/app/Http/Middleware/Custom/AdminsOnly.php b/app/Http/Middleware/Custom/AdminsOnly.php new file mode 100644 index 00000000..c2f6399e --- /dev/null +++ b/app/Http/Middleware/Custom/AdminsOnly.php @@ -0,0 +1,24 @@ +hasRole("admin")) + { + abort(403, 'Unauthorized'); + } + return $next($request); + } +} diff --git a/app/User.php b/app/User.php index d6ee859e..bd077843 100644 --- a/app/User.php +++ b/app/User.php @@ -55,6 +55,18 @@ protected static function boot() }); } + /** + * For an account to be in considered pending the + * user must have confirmed their email address. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopePending ($query) + { + return $query->where('approved', '=', 'N')->where('confirmed_email', '=', 'Y'); + } + /** * Set the ip address attribute. * @@ -74,8 +86,22 @@ public function roles() { return $this->belongsToMany('App\Role'); } + /** + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeThisYear ($query) + { + // TODO: Query current year... + return $query; + } + /** * Whether or not the user has reached their limit of nominations for the year + * + * TODO: Rejected nominations should not count toward the limit + * TODO: Need to use current year for limit + * * @return bool */ public function getMaxNominationsReachedAttribute() diff --git a/resources/views/admin/affiliations/index.blade.php b/resources/views/admin/affiliations/index.blade.php index 69e4c807..02a7635d 100644 --- a/resources/views/admin/affiliations/index.blade.php +++ b/resources/views/admin/affiliations/index.blade.php @@ -3,7 +3,7 @@ @section('content')
-
+
diff --git a/resources/views/admin/dashboard/index.blade.php b/resources/views/admin/dashboard/index.blade.php index f4886cf9..c6913eda 100644 --- a/resources/views/admin/dashboard/index.blade.php +++ b/resources/views/admin/dashboard/index.blade.php @@ -1,10 +1,67 @@ @extends('layouts.admin', ['no_boxes' => true]) @section('content') + @if (Auth::user()->hasRole('admin'))
-
- +
+
+
+

+ Quick Overview +

+
+
+ + + + + + + + {{-- TODO Waiting for #30 + + + + + + + + + --}} + + + + + +
+ Accounts pending approval + + {{ $accounts_pending_approval }} + + +
+ Nominations Pending Review + + -- + + +
+ Nominations approved / reviewed + + -- / -- +
+ Incomplete drafts + + {{$drafts}} +
+
+
+ @endif {{--Admins only--}} @endsection \ No newline at end of file diff --git a/resources/views/admin/households/index.blade.php b/resources/views/admin/households/index.blade.php index 2139b3d1..8accc28d 100644 --- a/resources/views/admin/households/index.blade.php +++ b/resources/views/admin/households/index.blade.php @@ -4,7 +4,7 @@
-
+
diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php index 5e8e9f51..341d508d 100644 --- a/resources/views/admin/users/index.blade.php +++ b/resources/views/admin/users/index.blade.php @@ -3,7 +3,7 @@ @section('content')
-
+
diff --git a/resources/views/admin/users/pending.blade.php b/resources/views/admin/users/pending.blade.php index dab3b936..5d65ebc4 100644 --- a/resources/views/admin/users/pending.blade.php +++ b/resources/views/admin/users/pending.blade.php @@ -3,7 +3,7 @@ @section('content')
-
+
diff --git a/resources/views/partials/forms/household.blade.php b/resources/views/partials/forms/household.blade.php index 56fd7aa8..4d4efa77 100644 --- a/resources/views/partials/forms/household.blade.php +++ b/resources/views/partials/forms/household.blade.php @@ -556,6 +556,7 @@ + Saved!
@@ -581,6 +582,7 @@ data: { loading: false, saving: false, + showSavedMessage: false, schools: [], household: { phone: [], @@ -771,7 +773,7 @@ function(results, status) { if (this.saving === true) return; // Already in the middle of saving >:( - + this.showSavedMessage= false; this.saving = true; // Refuse to submit if required fields are empty, and highlight missing fields @@ -824,6 +826,7 @@ function(results, status) if (data.ok) { self.household = data.household[0]; + self.showSavedMessage= true; } else if (!data.ok && typeof data.message != "undefined") {