Merge user feeds & followers #118
@ -133,6 +133,7 @@ class ConfigHelper
|
|||||||
'social_facebook_login' => false,
|
'social_facebook_login' => false,
|
||||||
'social_google_login' => false,
|
'social_google_login' => false,
|
||||||
'social_twitter_login' => false,
|
'social_twitter_login' => false,
|
||||||
|
'social_user_feeds' => false,
|
||||||
'social_user_profiles' => false,
|
'social_user_profiles' => false,
|
||||||
'theme' => 'default',
|
'theme' => 'default',
|
||||||
'twitter_app_id' => '',
|
'twitter_app_id' => '',
|
||||||
@ -187,6 +188,7 @@ class ConfigHelper
|
|||||||
public function isSocialMediaLoginEnabled()
|
public function isSocialMediaLoginEnabled()
|
||||||
{
|
{
|
||||||
return $this->get('social_facebook_login') ||
|
return $this->get('social_facebook_login') ||
|
||||||
$this->get('social_twitter_login');
|
$this->get('social_twitter_login') ||
|
||||||
|
$this->get('social_google_login');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -249,6 +249,7 @@ class DefaultController extends Controller
|
|||||||
'social_facebook_login',
|
'social_facebook_login',
|
||||||
'social_google_login',
|
'social_google_login',
|
||||||
'social_twitter_login',
|
'social_twitter_login',
|
||||||
|
'social_user_feeds',
|
||||||
'social_user_profiles'
|
'social_user_profiles'
|
||||||
];
|
];
|
||||||
$updateKeys = [
|
$updateKeys = [
|
||||||
|
@ -15,6 +15,8 @@ use App\Photo;
|
|||||||
use App\Services\PhotoService;
|
use App\Services\PhotoService;
|
||||||
use App\Upload;
|
use App\Upload;
|
||||||
use App\UploadPhoto;
|
use App\UploadPhoto;
|
||||||
|
use App\User;
|
||||||
|
use App\UserActivity;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
@ -52,6 +54,15 @@ class PhotoController extends Controller
|
|||||||
$photoService = new PhotoService($photo);
|
$photoService = new PhotoService($photo);
|
||||||
$photoService->analyse($queue_token);
|
$photoService->analyse($queue_token);
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed (remove an existing one as the date may have changed)
|
||||||
|
$this->removeExistingActivityRecords($photo, 'photo.taken');
|
||||||
|
|
||||||
|
if (!is_null($photo->taken_at))
|
||||||
|
{
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.taken', $photo->taken_at);
|
||||||
|
}
|
||||||
|
|
||||||
$result['is_successful'] = true;
|
$result['is_successful'] = true;
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
@ -115,6 +126,9 @@ class PhotoController extends Controller
|
|||||||
|
|
||||||
$photoService = new PhotoService($photo);
|
$photoService = new PhotoService($photo);
|
||||||
$photoService->flip($horizontal, $vertical);
|
$photoService->flip($horizontal, $vertical);
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.edited');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function move(Request $request, $photoId)
|
public function move(Request $request, $photoId)
|
||||||
@ -158,6 +172,15 @@ class PhotoController extends Controller
|
|||||||
$photoService->downloadOriginalToFolder(FileHelper::getQueuePath($queue_token));
|
$photoService->downloadOriginalToFolder(FileHelper::getQueuePath($queue_token));
|
||||||
$photoService->analyse($queue_token);
|
$photoService->analyse($queue_token);
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed (remove an existing one as the date may have changed)
|
||||||
|
$this->removeExistingActivityRecords($photo, 'photo.taken');
|
||||||
|
|
||||||
|
if (!is_null($photo->taken_at))
|
||||||
|
{
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.taken', $photo->taken_at);
|
||||||
|
}
|
||||||
|
|
||||||
$result['is_successful'] = true;
|
$result['is_successful'] = true;
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
@ -209,6 +232,9 @@ class PhotoController extends Controller
|
|||||||
|
|
||||||
$photoService = new PhotoService($photo);
|
$photoService = new PhotoService($photo);
|
||||||
$photoService->rotate($angle);
|
$photoService->rotate($angle);
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.edited');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,6 +279,9 @@ class PhotoController extends Controller
|
|||||||
|
|
||||||
/** @var File $savedFile */
|
/** @var File $savedFile */
|
||||||
$savedFile = FileHelper::saveUploadedFile($photoFile, $queueFolder, $photo->storage_file_name);
|
$savedFile = FileHelper::saveUploadedFile($photoFile, $queueFolder, $photo->storage_file_name);
|
||||||
|
|
||||||
|
$this->removeExistingActivityRecords($photo, 'photo.uploaded');
|
||||||
|
$this->removeExistingActivityRecords($photo, 'photo.taken');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -272,6 +301,9 @@ class PhotoController extends Controller
|
|||||||
$photo->is_analysed = false;
|
$photo->is_analysed = false;
|
||||||
$photo->save();
|
$photo->save();
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.uploaded');
|
||||||
|
|
||||||
$isSuccessful = true;
|
$isSuccessful = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,6 +413,10 @@ class PhotoController extends Controller
|
|||||||
$photo->file_size = $savedFile->getSize();
|
$photo->file_size = $savedFile->getSize();
|
||||||
$photo->is_analysed = false;
|
$photo->is_analysed = false;
|
||||||
$photo->save();
|
$photo->save();
|
||||||
|
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.uploaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(route('albums.analyse', [
|
return redirect(route('albums.analyse', [
|
||||||
@ -566,6 +602,12 @@ class PhotoController extends Controller
|
|||||||
$photo->save();
|
$photo->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!in_array(strtolower($action), ['delete', 'refresh_thumbnails', 'change_album']))
|
||||||
|
{
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createActivityRecord($photo, 'photo.edited');
|
||||||
|
}
|
||||||
|
|
||||||
if ($changed)
|
if ($changed)
|
||||||
{
|
{
|
||||||
$numberChanged++;
|
$numberChanged++;
|
||||||
@ -575,6 +617,21 @@ class PhotoController extends Controller
|
|||||||
return $numberChanged;
|
return $numberChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createActivityRecord(Photo $photo, $type, $activityDateTime = null)
|
||||||
|
{
|
||||||
|
if (is_null($activityDateTime))
|
||||||
|
{
|
||||||
|
$activityDateTime = new \DateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
$userActivity = new UserActivity();
|
||||||
|
$userActivity->user_id = $this->getUser()->id;
|
||||||
|
$userActivity->activity_at = $activityDateTime;
|
||||||
|
$userActivity->type = $type;
|
||||||
|
$userActivity->photo_id = $photo->id;
|
||||||
|
$userActivity->save();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return Album
|
* @return Album
|
||||||
@ -615,6 +672,20 @@ class PhotoController extends Controller
|
|||||||
return $photo;
|
return $photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function removeExistingActivityRecords(Photo $photo, $type)
|
||||||
|
{
|
||||||
|
$existingFeedRecords = UserActivity::where([
|
||||||
|
'user_id' => $this->getUser()->id,
|
||||||
|
'photo_id' => $photo->id,
|
||||||
|
'type' => $type
|
||||||
|
])->get();
|
||||||
|
|
||||||
|
foreach ($existingFeedRecords as $existingFeedRecord)
|
||||||
|
{
|
||||||
|
$existingFeedRecord->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function updatePhotoDetails(Request $request, Album $album)
|
private function updatePhotoDetails(Request $request, Album $album)
|
||||||
{
|
{
|
||||||
$numberChanged = 0;
|
$numberChanged = 0;
|
||||||
|
@ -12,10 +12,12 @@ use App\Http\Requests\StorePhotoCommentRequest;
|
|||||||
use App\Mail\ModeratePhotoComment;
|
use App\Mail\ModeratePhotoComment;
|
||||||
use App\Mail\PhotoCommentApproved;
|
use App\Mail\PhotoCommentApproved;
|
||||||
use App\Mail\PhotoCommentApprovedUser;
|
use App\Mail\PhotoCommentApprovedUser;
|
||||||
|
use App\Mail\PhotoCommentRepliedTo;
|
||||||
use App\Permission;
|
use App\Permission;
|
||||||
use App\Photo;
|
use App\Photo;
|
||||||
use App\PhotoComment;
|
use App\PhotoComment;
|
||||||
use App\User;
|
use App\User;
|
||||||
|
use App\UserActivity;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
@ -54,6 +56,7 @@ class PhotoCommentController extends Controller
|
|||||||
$comment->approved_user_id = $this->getUser()->id;
|
$comment->approved_user_id = $this->getUser()->id;
|
||||||
$comment->save();
|
$comment->save();
|
||||||
|
|
||||||
|
$this->createUserActivityRecord($comment);
|
||||||
$this->notifyAlbumOwnerAndPoster($album, $photo, $comment);
|
$this->notifyAlbumOwnerAndPoster($album, $photo, $comment);
|
||||||
$request->getSession()->flash('success', trans('gallery.photo_comment_approved_successfully'));
|
$request->getSession()->flash('success', trans('gallery.photo_comment_approved_successfully'));
|
||||||
}
|
}
|
||||||
@ -191,6 +194,8 @@ class PhotoCommentController extends Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Log an activity record for the user's feed
|
||||||
|
$this->createUserActivityRecord($comment);
|
||||||
$this->notifyAlbumOwnerAndPoster($album, $photo, $comment);
|
$this->notifyAlbumOwnerAndPoster($album, $photo, $comment);
|
||||||
$request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
|
$request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
|
||||||
}
|
}
|
||||||
@ -223,6 +228,29 @@ class PhotoCommentController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createUserActivityRecord(PhotoComment $comment)
|
||||||
|
{
|
||||||
|
if (!is_null($comment->created_user_id))
|
||||||
|
{
|
||||||
|
$userActivity = new UserActivity();
|
||||||
|
$userActivity->user_id = $comment->created_user_id;
|
||||||
|
$userActivity->activity_at = $comment->created_at;
|
||||||
|
|
||||||
|
if (is_null($comment->parent_comment_id))
|
||||||
|
{
|
||||||
|
$userActivity->type = 'photo.commented';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$userActivity->type = 'photo.comment_replied';
|
||||||
|
}
|
||||||
|
|
||||||
|
$userActivity->photo_id = $comment->photo_id;
|
||||||
|
$userActivity->photo_comment_id = $comment->id;
|
||||||
|
$userActivity->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function loadAlbumPhotoComment($albumUrlAlias, $photoFilename, $commentID, &$album, &$photo, &$comment)
|
private function loadAlbumPhotoComment($albumUrlAlias, $photoFilename, $commentID, &$album, &$photo, &$comment)
|
||||||
{
|
{
|
||||||
$album = DbHelper::getAlbumByPath($albumUrlAlias);
|
$album = DbHelper::getAlbumByPath($albumUrlAlias);
|
||||||
@ -256,6 +284,22 @@ class PhotoCommentController extends Controller
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a given comment by its ID.
|
||||||
|
* @param $id
|
||||||
|
* @return PhotoComment
|
||||||
|
*/
|
||||||
|
private function loadCommentByID($id)
|
||||||
|
{
|
||||||
|
$comment = PhotoComment::where('id', intval($id))->first();
|
||||||
|
if (is_null($comment))
|
||||||
|
{
|
||||||
|
App::abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an e-mail notification to an album's moderators that a comment is available to moderate.
|
* Sends an e-mail notification to an album's moderators that a comment is available to moderate.
|
||||||
* @param Album $album
|
* @param Album $album
|
||||||
|
@ -10,6 +10,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Http\Requests\SaveUserSettingsRequest;
|
use App\Http\Requests\SaveUserSettingsRequest;
|
||||||
use App\Mail\UserChangeEmailRequired;
|
use App\Mail\UserChangeEmailRequired;
|
||||||
use App\User;
|
use App\User;
|
||||||
|
use App\UserActivity;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
@ -118,16 +119,7 @@ class UserController extends Controller
|
|||||||
|
|
||||||
public function show(Request $request, $idOrAlias)
|
public function show(Request $request, $idOrAlias)
|
||||||
{
|
{
|
||||||
// If a user has a profile alias set, their profile page cannot be accessed by the ID
|
$user = $this->loadUserProfilePage($idOrAlias);
|
||||||
$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);
|
|
||||||
|
|
||||||
$albums = $this->getAlbumsForUser($user);
|
$albums = $this->getAlbumsForUser($user);
|
||||||
$albumIDs = $this->getAlbumIDsForUser($user);
|
$albumIDs = $this->getAlbumIDsForUser($user);
|
||||||
@ -137,6 +129,7 @@ class UserController extends Controller
|
|||||||
$daysInMonth = $this->getDaysInMonths();
|
$daysInMonth = $this->getDaysInMonths();
|
||||||
|
|
||||||
return Theme::render('gallery.user_profile', [
|
return Theme::render('gallery.user_profile', [
|
||||||
|
'active_tab' => $request->get('tab'),
|
||||||
'activity_taken' => $this->constructActivityGrid($activity['taken']),
|
'activity_taken' => $this->constructActivityGrid($activity['taken']),
|
||||||
'activity_uploaded' => $this->constructActivityGrid($activity['uploaded']),
|
'activity_uploaded' => $this->constructActivityGrid($activity['uploaded']),
|
||||||
'albums' => $albums,
|
'albums' => $albums,
|
||||||
@ -146,6 +139,46 @@ class UserController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function showFeedJson(Request $request, $idOrAlias)
|
||||||
|
{
|
||||||
|
$user = $this->loadUserProfilePage($idOrAlias);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$activities = UserActivity::with('photo')
|
||||||
|
->with('photoComment')
|
||||||
|
->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;
|
||||||
|
$params['photo_name'] = $activity->photo->name;
|
||||||
|
$params['photo_url'] = $activity->photo->url();
|
||||||
|
$newItem['params'] = $params;
|
||||||
|
|
||||||
|
$result[] = $newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($result);
|
||||||
|
}
|
||||||
|
|
||||||
private function constructActivityGrid(Collection $collection)
|
private function constructActivityGrid(Collection $collection)
|
||||||
{
|
{
|
||||||
$results = [];
|
$results = [];
|
||||||
@ -300,6 +333,26 @@ class UserController extends Controller
|
|||||||
return $results;
|
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)
|
private function sendEmailChangeConfirmationEmail(User $user, $newEmailAddress)
|
||||||
{
|
{
|
||||||
$oldEmailAddress = $user->email;
|
$oldEmailAddress = $user->email;
|
||||||
|
@ -55,6 +55,13 @@ class User extends Authenticatable
|
|||||||
return $this->hasMany(Album::class);
|
return $this->hasMany(Album::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function feedJsonUrl()
|
||||||
|
{
|
||||||
|
return route('viewUserFeedJson', [
|
||||||
|
'idOrAlias' => (!empty($this->profile_alias) ? trim(strtolower($this->profile_alias)) : $this->id)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function groups()
|
public function groups()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Group::class, 'user_groups');
|
return $this->belongsToMany(Group::class, 'user_groups');
|
||||||
|
20
app/UserActivity.php
Normal file
20
app/UserActivity.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserActivity extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'user_activity';
|
||||||
|
|
||||||
|
public function photo()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Photo::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function photoComment()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PhotoComment::class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateUserActivitiesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('user_activity', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->unsignedInteger('user_id');
|
||||||
|
$table->dateTime('activity_at');
|
||||||
|
$table->string('type', 100);
|
||||||
|
$table->unsignedBigInteger('photo_id')->nullable(true);
|
||||||
|
$table->unsignedBigInteger('photo_comment_id')->nullable(true);
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->foreign('user_id')
|
||||||
|
->references('id')->on('users')
|
||||||
|
->onDelete('cascade');
|
||||||
|
$table->foreign('photo_id')
|
||||||
|
->references('id')->on('photos')
|
||||||
|
->onDelete('cascade');
|
||||||
|
$table->foreign('photo_comment_id')
|
||||||
|
->references('id')->on('photo_comments')
|
||||||
|
->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_activity');
|
||||||
|
}
|
||||||
|
}
|
@ -74,3 +74,77 @@ function PhotoViewModel(urls) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This model is used by gallery/user_profile.blade.php, to handle a user's profile.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function UserViewModel(urls)
|
||||||
|
{
|
||||||
|
this.el = '#user-app';
|
||||||
|
|
||||||
|
this.data = {
|
||||||
|
feed_items: [],
|
||||||
|
is_loading: true,
|
||||||
|
selected_view: 'profile'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.computed = {
|
||||||
|
isFeed: function() {
|
||||||
|
return this.selected_view === 'feed';
|
||||||
|
},
|
||||||
|
isProfile: function() {
|
||||||
|
return this.selected_view === 'profile';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.methods = {
|
||||||
|
loadFeedItems: function(e)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$.get(urls.feed_url, function (data)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < data.length; i++)
|
||||||
|
{
|
||||||
|
// User name
|
||||||
|
if (data[i].params.user_name && data[i].params.user_url)
|
||||||
|
{
|
||||||
|
data[i].description = data[i].description
|
||||||
|
.replace(
|
||||||
|
':user_name',
|
||||||
|
'<a href="' + data[i].params.user_url + '">' + data[i].params.user_name + '</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Photo name
|
||||||
|
if (data[i].params.photo_name && data[i].params.photo_url)
|
||||||
|
{
|
||||||
|
data[i].description = data[i].description
|
||||||
|
.replace(
|
||||||
|
':photo_name',
|
||||||
|
'<a href="' + data[i].params.photo_url + '">' + data[i].params.photo_name + '</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.feed_items = data;
|
||||||
|
self.is_loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
switchToFeed: function(e) {
|
||||||
|
this.selected_view = 'feed';
|
||||||
|
history.pushState('data to be passed', 'Title of the page', urls.current_url + '?tab=feed');
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
switchToProfile: function(e) {
|
||||||
|
this.selected_view = 'profile';
|
||||||
|
history.pushState('data to be passed', 'Title of the page', urls.current_url + '?tab=profile');
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -89,6 +89,8 @@ return [
|
|||||||
'settings_social_twitter_app_secret' => 'Twitter App Secret:',
|
'settings_social_twitter_app_secret' => 'Twitter App Secret:',
|
||||||
'settings_social_twitter_login' => 'Allow login/registration with a Twitter account',
|
'settings_social_twitter_login' => 'Allow login/registration with a Twitter account',
|
||||||
'settings_social_twitter_login_help' => 'With this option enabled, users can register (if enabled) and login with their Twitter account.',
|
'settings_social_twitter_login_help' => 'With this option enabled, users can register (if enabled) and login with their Twitter account.',
|
||||||
|
'settings_social_user_feeds' => 'Enable user feeds and following',
|
||||||
|
'settings_social_user_feeds_help' => 'Show activity feeds for users and allow users to follow others.',
|
||||||
'settings_social_user_profiles' => 'Enable public user profiles',
|
'settings_social_user_profiles' => 'Enable public user profiles',
|
||||||
'settings_social_user_profiles_help' => 'Display public pages for users showing their albums, cameras used and activity.',
|
'settings_social_user_profiles_help' => 'Display public pages for users showing their albums, cameras used and activity.',
|
||||||
'storage_access_key_label' => 'Access key:',
|
'storage_access_key_label' => 'Access key:',
|
||||||
|
@ -77,6 +77,15 @@ return [
|
|||||||
'title' => 'Statistics',
|
'title' => 'Statistics',
|
||||||
'uploaded_12_months' => 'Photos uploaded in the last 12 months',
|
'uploaded_12_months' => 'Photos uploaded in the last 12 months',
|
||||||
],
|
],
|
||||||
|
'user_feed_type' => [
|
||||||
|
'photo' => [
|
||||||
|
'comment_replied' => ':user_name replied to a comment on the :photo_name photo.',
|
||||||
|
'commented' => ':user_name commented on the :photo_name photo.',
|
||||||
|
'edited' => ':user_name edited the :photo_name photo.',
|
||||||
|
'taken' => ':user_name took the :photo_name photo.',
|
||||||
|
'uploaded' => ':user_name uploaded the :photo_name photo.'
|
||||||
|
]
|
||||||
|
],
|
||||||
'user_profile' => [
|
'user_profile' => [
|
||||||
'activity' => 'Activity',
|
'activity' => 'Activity',
|
||||||
'activity_summary' => ':count photo on :date|:count photos on :date',
|
'activity_summary' => ':count photo on :date|:count photos on :date',
|
||||||
@ -86,8 +95,10 @@ return [
|
|||||||
'activity_uploaded_tab' => 'Uploaded',
|
'activity_uploaded_tab' => 'Uploaded',
|
||||||
'albums' => 'Albums by :user_name',
|
'albums' => 'Albums by :user_name',
|
||||||
'cameras' => 'Cameras',
|
'cameras' => 'Cameras',
|
||||||
|
'feed_tab' => 'Activity',
|
||||||
'no_albums_p1' => 'No Photo Albums',
|
'no_albums_p1' => 'No Photo Albums',
|
||||||
'no_albums_p2' => ':user_name has not created any albums yet.'
|
'no_albums_p2' => ':user_name has not created any albums yet.',
|
||||||
|
'profile_tab' => 'Profile'
|
||||||
],
|
],
|
||||||
'user_settings' => [
|
'user_settings' => [
|
||||||
'cancel_email_change' => 'Don\'t change e-mail address',
|
'cancel_email_change' => 'Don\'t change e-mail address',
|
||||||
|
@ -346,6 +346,14 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mt-3">
|
||||||
|
<input type="checkbox" class="form-check-input" id="social-user-feeds" name="social_user_feeds" @if (old('social_user_feeds', UserConfig::get('social_user_feeds')))checked="checked"@endif>
|
||||||
|
<label class="form-check-label" for="social-user-feeds">
|
||||||
|
<strong>@lang('forms.settings_social_user_feeds')</strong><br/>
|
||||||
|
@lang('forms.settings_social_user_feeds_help')
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr class="mt-4 mb-4"/>
|
<hr class="mt-4 mb-4"/>
|
||||||
|
|
||||||
{{-- Facebook --}}
|
{{-- Facebook --}}
|
||||||
@ -440,6 +448,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr class="mt-4 mb-4"/>
|
||||||
|
|
||||||
{{-- Google+ --}}
|
{{-- Google+ --}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-2 col-sm-1">
|
<div class="col-2 col-sm-1">
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container">
|
<div class="container" id="user-app">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div id="user-avatar" class="col-sm-4 col-md-3 col-xl-2 mb-3">
|
<div id="user-avatar" class="col-sm-4 col-md-3 col-xl-2 mb-3">
|
||||||
<img class="rounded" src="{{ Theme::gravatarUrl($user->email, 160) }}" title="{{ $user->name }}" />
|
<img class="rounded" src="{{ Theme::gravatarUrl($user->email, 160) }}" title="{{ $user->name }}" />
|
||||||
@ -21,7 +21,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-5">
|
<div class="row mt-3">
|
||||||
|
<div class="col">
|
||||||
|
<ul class="nav nav-pills">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url()->current() }}" v-bind:class="{ active: isProfile }" v-on:click="switchToProfile"><i class="fa fa-fw fa-info-circle"></i> @lang('gallery.user_profile.profile_tab')</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url()->current() }}" v-bind:class="{ active: isFeed }" v-on:click="switchToFeed"><i class="fa fa-fw fa-clock-o"></i> @lang('gallery.user_profile.feed_tab')</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-5" v-if="selected_view === 'profile'">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@if (count($albums) == 0)
|
@if (count($albums) == 0)
|
||||||
<h4 class="text-danger"><b>@lang('gallery.user_profile.no_albums_p1')</b></h4>
|
<h4 class="text-danger"><b>@lang('gallery.user_profile.no_albums_p1')</b></h4>
|
||||||
@ -87,5 +100,49 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-5" v-if="selected_view === 'feed'">
|
||||||
|
<div class="col">
|
||||||
|
<div v-if="is_loading">
|
||||||
|
<p class="text-center mb-1">
|
||||||
|
<img src="{{ asset('ripple.svg') }}" alt="@lang('global.please_wait')" title="@lang('global.please_wait')"/>
|
||||||
|
</p>
|
||||||
|
<p class="text-center">
|
||||||
|
@lang('global.please_wait')
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="feed_items.length > 0">
|
||||||
|
<div class="card mb-2" v-for="feed_item in feed_items">
|
||||||
|
<div class="card-body row">
|
||||||
|
<div class="col-2 col-md-1 pr-0" style="max-width: 47px;">
|
||||||
|
<img class="rounded-circle" v-bind:src="feed_item.avatar"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-10 col-md-11">
|
||||||
|
<span v-html="feed_item.description"></span><br/>
|
||||||
|
<span class="text-muted" style="font-size: smaller;" v-html="feed_item.activity_at"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
var viewModel = new UserViewModel({
|
||||||
|
current_url: '{{ url()->current() }}',
|
||||||
|
feed_url: '{{ \App\User::currentOrAnonymous()->feedJsonUrl() }}'
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = new Vue(viewModel);
|
||||||
|
app.loadFeedItems();
|
||||||
|
|
||||||
|
@if ($active_tab == 'feed')
|
||||||
|
app.selected_view = 'feed';
|
||||||
|
@elseif ($active_tab == 'profile')
|
||||||
|
app.selected_view = 'profile';
|
||||||
|
@endif
|
||||||
|
</script>
|
||||||
|
@endpush
|
@ -140,6 +140,9 @@ Route::get('i/{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@downloa
|
|||||||
Route::get('label/{labelAlias}', 'Gallery\LabelController@show')
|
Route::get('label/{labelAlias}', 'Gallery\LabelController@show')
|
||||||
->name('viewLabel')
|
->name('viewLabel')
|
||||||
->where('labelAlias', '.*');
|
->where('labelAlias', '.*');
|
||||||
|
Route::get('u/{idOrAlias}/feed.json', 'Gallery\UserController@showFeedJson')
|
||||||
|
->name('viewUserFeedJson')
|
||||||
|
->where('idOrAlias', '.*');
|
||||||
Route::get('u/{idOrAlias}', 'Gallery\UserController@show')
|
Route::get('u/{idOrAlias}', 'Gallery\UserController@show')
|
||||||
->name('viewUser')
|
->name('viewUser')
|
||||||
->where('idOrAlias', '.*');
|
->where('idOrAlias', '.*');
|
||||||
|
Loading…
Reference in New Issue
Block a user