blue-twilight/app/Http/Controllers/Gallery/UserController.php

516 lines
16 KiB
PHP

<?php
namespace App\Http\Controllers\Gallery;
use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Helpers\DbHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserSettingsRequest;
use App\Mail\UserChangeEmailRequired;
use App\User;
use App\UserActivity;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Symfony\Component\HttpFoundation\Request;
class UserController extends Controller
{
public function activityFeed()
{
if (!UserConfig::get('social_user_feeds'))
{
return redirect(route('home'));
}
return Theme::render('gallery.user_activity_feed', [
'user' => $this->getUser()
]);
}
public function activityFeedJson()
{
if (!UserConfig::get('social_user_feeds'))
{
return response()->json(['message' => 'Activity feeds not enabled']);
}
$user = $this->getUser();
$result = [];
$activities = UserActivity::with('photo')
->with('photoComment')
->with('user')
->join('user_followers', 'user_followers.following_user_id', '=', 'user_activity.user_id')
->where([
'user_followers.user_id' => $user->id
])
->orderBy('activity_at', 'desc')
->limit(100) // TODO: make this configurable
->select('user_activity.*')
->get();
/** @var UserActivity $activity */
foreach ($activities as $activity)
{
$userName = $activity->user->name;
$userProfileUrl = $activity->user->profileUrl();
$userAvatar = Theme::gravatarUrl($activity->user->email, 32);
$newItem = [
'activity_at' => date(UserConfig::get('date_format'), strtotime($activity->activity_at)),
'avatar' => $userAvatar,
'description' => trans(sprintf('gallery.user_feed_type.%s', $activity->type))
];
$params = [];
$params['user_name'] = $userName;
$params['user_url'] = $userProfileUrl;
if (!is_null($activity->photo))
{
// Check the user has access
if (!$this->getUser()->can('view', $activity->photo))
{
continue;
}
$params['photo_name'] = $activity->photo->name;
$params['photo_url'] = $activity->photo->url();
}
if (!is_null($activity->album))
{
// Check the user has access
if (!$this->getUser()->can('view', $activity->album))
{
continue;
}
$params['album_name'] = $activity->album->name;
$params['album_url'] = $activity->album->url();
}
$newItem['params'] = $params;
$result[] = $newItem;
}
return response()->json($result);
}
public function confirmEmailChangeState(Request $request)
{
$user = $this->getUser();
if (!$user->is_email_change_in_progress)
{
return redirect(route('userSettings'));
}
// Update the e-mail address
$user->email = $user->new_email_address;
// Reset the e-mail change state
$user->is_email_change_in_progress = false;
$user->new_email_address = null;
$user->save();
$request->session()->flash('success', trans('auth.change_email_success_message'));
return redirect(route('userSettings'));
}
public function followUser($idOrAlias)
{
$user = $this->loadUserProfilePage($idOrAlias);
$isFollowing = $this->getUser()->following()->where('following_user_id', $user->id)->count() > 0;
if (!$isFollowing)
{
$this->getUser()->following()->attach(
$user->id,
[
'created_at' => new \DateTime(),
'updated_at' => new \DateTime()
]
);
}
return response()->json(true);
}
public function resetEmailChangeState(Request $request)
{
$user = $this->getUser();
if (!$user->is_email_change_in_progress)
{
return redirect(route('userSettings'));
}
$data = $request->all();
if (isset($data['resend_email']))
{
$this->sendEmailChangeConfirmationEmail($user, $user->new_email_address);
$request->session()->flash('info', trans('auth.change_email_required_message'));
}
if (isset($data['cancel_change']))
{
$user->is_email_change_in_progress = false;
$user->new_email_address = null;
$user->save();
}
return redirect(route('userSettings'));
}
public function saveSettings(SaveUserSettingsRequest $request)
{
$data = $request->only(['name', 'email', 'profile_alias', 'enable_profile_page']);
$user = $this->getUser();
if (
UserConfig::get('require_email_verification') &&
isset($data['email']) &&
$data['email'] != $user->email &&
!$user->is_email_change_in_progress
)
{
// Can't update the e-mail directly until the new e-mail address has been verified.
// TODO - send e-mail and handle response, flag e-mail as being "change in-progress"
// Send activation e-mail
$this->sendEmailChangeConfirmationEmail($user, $data['email']);
$request->session()->flash('info', trans('auth.change_email_required_message'));
// Flag the user as a change e-mail in progress
$user->new_email_address = $data['email'];
$user->is_email_change_in_progress = true;
$user->save();
unset($data['email']);
$request->session()->flash('info', trans('auth.change_email_required_message'));
}
// Don't allow e-mail address to be changed if a change is in progress
if ($user->is_email_change_in_progress)
{
unset($data['email']);
}
$user->fill($data);
$user->enable_profile_page = (isset($data['enable_profile_page']) && strtolower($data['enable_profile_page']) == 'on');
$user->save();
$request->session()->flash('success', trans('gallery.user_settings.settings_saved'));
return redirect(route('userSettings'));
}
public function settings(Request $request)
{
return Theme::render('gallery.user_settings', [
'info' => $request->session()->get('info'),
'success' => $request->session()->get('success'),
'user' => $this->getUser()
]);
}
public function show(Request $request, $idOrAlias)
{
$user = $this->loadUserProfilePage($idOrAlias);
$albums = $this->getAlbumsForUser($user);
$albumIDs = $this->getAlbumIDsForUser($user);
$cameras = $this->getCamerasUsedInAlbums($albumIDs);
$activity = $this->getActivityDatesInAlbums($albumIDs);
$daysInMonth = $this->getDaysInMonths();
// Only logged-in users can follow other users (and if it's not their own page!)
$canFollow = !$this->getUser()->isAnonymous() && $this->getUser()->id != $user->id;
$isFollowing = false;
if ($canFollow)
{
// Is the current user following this user?
$isFollowing = $this->getUser()->following()->where('following_user_id', $user->id)->count() > 0;
}
return Theme::render('gallery.user_profile', [
'active_tab' => $request->get('tab'),
'activity_taken' => $this->constructActivityGrid($activity['taken']),
'activity_uploaded' => $this->constructActivityGrid($activity['uploaded']),
'albums' => $albums,
'cameras' => $cameras,
'can_follow' => $canFollow,
'is_following' => $isFollowing,
'month_days' => $daysInMonth,
'user' => $user
]);
}
public function showFeedJson(Request $request, $idOrAlias)
{
$user = $this->loadUserProfilePage($idOrAlias);
$result = [];
$activities = UserActivity::with('photo')
->with('photoComment')
->with('album')
->where([
'user_id' => $user->id
])
->orderBy('activity_at', 'desc')
->limit(100) // TODO: make this configurable
->get();
$userName = $user->name;
$userProfileUrl = $user->profileUrl();
$userAvatar = Theme::gravatarUrl($user->email, 32);
/** @var UserActivity $activity */
foreach ($activities as $activity)
{
$newItem = [
'activity_at' => date(UserConfig::get('date_format'), strtotime($activity->activity_at)),
'avatar' => $userAvatar,
'description' => trans(sprintf('gallery.user_feed_type.%s', $activity->type))
];
$params = [];
$params['user_name'] = $userName;
$params['user_url'] = $userProfileUrl;
if (!is_null($activity->photo))
{
// Check the user has access
if (!$this->getUser()->can('view', $activity->photo))
{
continue;
}
$params['photo_name'] = $activity->photo->name;
$params['photo_url'] = $activity->photo->url();
}
if (!is_null($activity->album))
{
// Check the user has access
if (!$this->getUser()->can('view', $activity->album))
{
continue;
}
$params['album_name'] = $activity->album->name;
$params['album_url'] = $activity->album->url();
}
$newItem['params'] = $params;
$result[] = $newItem;
}
return response()->json($result);
}
public function unFollowUser($idOrAlias)
{
$user = $this->loadUserProfilePage($idOrAlias);
$isFollowing = $this->getUser()->following()->where('following_user_id', $user->id)->count() > 0;
if ($isFollowing)
{
$this->getUser()->following()->detach($user->id);
}
return response()->json(true);
}
private function constructActivityGrid(Collection $collection)
{
$results = [];
$lastYearFrom = new \DateTime();
$lastYearFrom->sub(new \DateInterval('P1Y'));
$lastYearFrom->add(new \DateInterval('P1D'));
$today = new \DateTime();
$current = clone $lastYearFrom;
while ($current < $today)
{
$year = intval($current->format('Y'));
$month = intval($current->format('m'));
$date = intval($current->format('d'));
if (!isset($results[$year]))
{
$results[$year] = [];
}
if (!isset($results[$year][$month]))
{
$results[$year][$month] = [];
}
if (!isset($results[$year][$month][$date]))
{
$results[$year][$month][$date] = 0;
}
$current->add(new \DateInterval('P1D'));
}
// Now update the totals from the collection
foreach ($collection as $photoInfo)
{
$date = \DateTime::createFromFormat('Y-m-d', $photoInfo->the_date);
$year = intval($date->format('Y'));
$month = intval($date->format('m'));
$date = intval($date->format('d'));
$results[$year][$month][$date] = $photoInfo->photos_count;
}
// Replace the month names
foreach ($results as $year => &$months)
{
foreach ($months as $month => $dates)
{
$monthDate = \DateTime::createFromFormat('m', $month);
$months[$monthDate->format('M')] = $dates;
unset($months[$month]);
}
}
return $results;
}
private function getActivityDatesInAlbums(array $albumIDs)
{
$createdAt = DB::table('photos')
->whereIn('album_id', $albumIDs)
->whereRaw(DB::raw('DATE(created_at) > DATE(DATE_SUB(NOW(), INTERVAL 1 year))'))
->select([
DB::raw('DATE(created_at) AS the_date'),
DB::raw('COUNT(photos.id) AS photos_count')
])
->groupBy(DB::raw('DATE(created_at)'))
->orderBy(DB::raw('DATE(created_at)'))
->get();
$takenAt = DB::table('photos')
->whereIn('album_id', $albumIDs)
->whereRaw(DB::raw('DATE(taken_at) > DATE(DATE_SUB(NOW(), INTERVAL 1 year))'))
->select([
DB::raw('DATE(taken_at) AS the_date'),
DB::raw('COUNT(photos.id) AS photos_count')
])
->groupBy(DB::raw('DATE(taken_at)'))
->orderBy(DB::raw('DATE(taken_at)'))
->get();
return ['uploaded' => $createdAt, 'taken' => $takenAt];
}
private function getAlbumsForUser(User $user)
{
return DbHelper::getAlbumsForCurrentUser_NonPaged()
->where('user_id', $user->id)
->paginate(UserConfig::get('items_per_page'));
}
private function getAlbumIDsForUser(User $user)
{
$results = [];
$albums = DbHelper::getAlbumsForCurrentUser_NonPaged()
->where('user_id', $user->id)
->select('albums.id')
->get();
foreach ($albums as $album)
{
$results[] = intval($album->id);
}
return $results;
}
private function getCamerasUsedInAlbums(array $albumIDs)
{
return DB::table('photos')
->whereIn('album_id', $albumIDs)
->where([
['camera_make', '!=', ''],
['camera_model', '!=', '']
])
->groupBy('camera_make', 'camera_model', 'camera_software')
->select('camera_make', 'camera_model', 'camera_software', DB::raw('count(*) as photo_count'))
->orderBy('photo_count', 'desc')
->orderBy('camera_make')
->orderBy('camera_model')
->orderBy('camera_software')
->get();
}
private function getDaysInMonths()
{
$results = [];
$lastYearFrom = new \DateTime();
$lastYearFrom->sub(new \DateInterval('P1Y'));
$lastYearFrom->sub(new \DateInterval(sprintf('P%dD', $lastYearFrom->format('d') - 1)));
$today = new \DateTime();
$current = clone $lastYearFrom;
while ($current < $today)
{
$year = intval($current->format('Y'));
$month = intval($current->format('m'));
$daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$results[$year][$current->format('M')] = $daysInMonth;
$current->add(new \DateInterval('P1M'));
}
return $results;
}
/**
* @param $idOrAlias
* @return User
*/
private function loadUserProfilePage($idOrAlias)
{
// If a user has a profile alias set, their profile page cannot be accessed by the ID
$user = User::where(DB::raw('COALESCE(profile_alias, id)'), strtolower($idOrAlias))->first();
if (is_null($user))
{
App::abort(404);
return null;
}
$this->authorizeForUser($this->getUser(), 'view', $user);
return $user;
}
private function sendEmailChangeConfirmationEmail(User $user, $newEmailAddress)
{
$oldEmailAddress = $user->email;
$user->email = $newEmailAddress;
Mail::to($user)->send(new UserChangeEmailRequired($user));
$user->email = $oldEmailAddress;
}
}