mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-22 04:58:01 +01:00
Account Settings
This commit is contained in:
parent
2a8bd3c85c
commit
ab3f15b5bf
9 changed files with 236 additions and 17 deletions
38
app/controllers/Api/Web/AccountController.php
Normal file
38
app/controllers/Api/Web/AccountController.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Api\Web;
|
||||||
|
|
||||||
|
use Commands\CreateAlbumCommand;
|
||||||
|
use Commands\DeleteAlbumCommand;
|
||||||
|
use Commands\DeleteTrackCommand;
|
||||||
|
use Commands\EditAlbumCommand;
|
||||||
|
use Commands\EditTrackCommand;
|
||||||
|
use Commands\SaveAccountSettingsCommand;
|
||||||
|
use Cover;
|
||||||
|
use Entities\Album;
|
||||||
|
use Entities\Image;
|
||||||
|
use Entities\Track;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Input;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
|
||||||
|
class AccountController extends \ApiControllerBase {
|
||||||
|
public function getSettings() {
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
return Response::json([
|
||||||
|
'bio' => $user->bio,
|
||||||
|
'can_see_explicit_content' => $user->can_see_explicit_content == 1,
|
||||||
|
'display_name' => $user->display_name,
|
||||||
|
'sync_names' => $user->sync_names == 1,
|
||||||
|
'mlpforums_name' => $user->mlpforums_name,
|
||||||
|
'gravatar' => $user->gravatar ? $user->gravatar : $user->email,
|
||||||
|
'avatar_url' => !$user->uses_gravatar ? $user->getAvatarUrl() : null,
|
||||||
|
'uses_gravatar' => $user->uses_gravatar == 1
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postSave() {
|
||||||
|
return $this->execute(new SaveAccountSettingsCommand(Input::all()));
|
||||||
|
}
|
||||||
|
}
|
79
app/models/Commands/SaveAccountSettingsCommand.php
Normal file
79
app/models/Commands/SaveAccountSettingsCommand.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Commands;
|
||||||
|
|
||||||
|
use Entities\Image;
|
||||||
|
use Entities\Track;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class SaveAccountSettingsCommand extends CommandBase {
|
||||||
|
private $_input;
|
||||||
|
|
||||||
|
function __construct($input) {
|
||||||
|
$this->_input = $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() {
|
||||||
|
return Auth::user() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
* @return CommandResponse
|
||||||
|
*/
|
||||||
|
public function execute() {
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'display_name' => 'required|min:3|max:26',
|
||||||
|
'bio' => 'textarea_length:250'
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->_input['sync_names'] == 'true')
|
||||||
|
$this->_input['display_name'] = $user->mlpforums_name;
|
||||||
|
|
||||||
|
if ($this->_input['uses_gravatar'] == 'true') {
|
||||||
|
$rules['gravatar'] = 'email';
|
||||||
|
} else {
|
||||||
|
$rules['avatar'] = 'image|mimes:png|min_width:350|min_height:350';
|
||||||
|
$rules['avatar_id'] = 'exists:images,id';
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = Validator::make($this->_input, $rules);
|
||||||
|
|
||||||
|
if ($validator->fails())
|
||||||
|
return CommandResponse::fail($validator);
|
||||||
|
|
||||||
|
if ($this->_input['uses_gravatar'] != 'true') {
|
||||||
|
if ($user->avatar_id == null && !isset($this->_input['avatar']) && !isset($this->_input['avatar_id'])) {
|
||||||
|
$validator->messages()->add('avatar', 'You must upload or select an avatar if you are not using gravatar!');
|
||||||
|
return CommandResponse::fail($validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->bio = $this->_input['bio'];
|
||||||
|
$user->display_name = $this->_input['display_name'];
|
||||||
|
$user->sync_names = $this->_input['sync_names'] == 'true';
|
||||||
|
$user->can_see_explicit_content = $this->_input['can_see_explicit_content'] == 'true';
|
||||||
|
$user->uses_gravatar = $this->_input['uses_gravatar'] == 'true';
|
||||||
|
|
||||||
|
if ($user->uses_gravatar) {
|
||||||
|
$user->avatar_id = null;
|
||||||
|
$user->gravatar = $this->_input['gravatar'];
|
||||||
|
} else {
|
||||||
|
if (isset($this->_input['avatar_id']))
|
||||||
|
$user->avatar_id = $this->_input['avatar_id'];
|
||||||
|
else if (isset($this->_input['avatar']))
|
||||||
|
$user->avatar_id = Image::upload($this->_input['avatar'], $user)->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return CommandResponse::succeed();
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,16 +67,16 @@
|
||||||
|
|
||||||
protected $table = 'images';
|
protected $table = 'images';
|
||||||
|
|
||||||
public function getUrl($type = Cover::NORMAL) {
|
public function getUrl($type = self::NORMAL) {
|
||||||
$type = self::$ImageTypes[$type];
|
$type = self::$ImageTypes[$type];
|
||||||
return URL::to('i' . $this->id . '/' . $type['name'] . '.png');
|
return URL::to('i' . $this->id . '/' . $type['name'] . '.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFile($type = Cover::NORMAL) {
|
public function getFile($type = self::NORMAL) {
|
||||||
return $this->getDirectory() . '/' . $this->getFilename($type);
|
return $this->getDirectory() . '/' . $this->getFilename($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFilename($type = Cover::NORMAL) {
|
public function getFilename($type = self::NORMAL) {
|
||||||
$typeInfo = self::$ImageTypes[$type];
|
$typeInfo = self::$ImageTypes[$type];
|
||||||
return $this->id . '_' . $typeInfo['name'] . '.png';
|
return $this->id . '_' . $typeInfo['name'] . '.png';
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,14 @@
|
||||||
use Gravatar;
|
use Gravatar;
|
||||||
use Illuminate\Auth\UserInterface;
|
use Illuminate\Auth\UserInterface;
|
||||||
use Illuminate\Auth\Reminders\RemindableInterface;
|
use Illuminate\Auth\Reminders\RemindableInterface;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
use Ratchet\Wamp\Exception;
|
||||||
|
|
||||||
class User extends \Eloquent implements UserInterface, RemindableInterface {
|
class User extends \Eloquent implements UserInterface, RemindableInterface {
|
||||||
protected $table = 'users';
|
protected $table = 'users';
|
||||||
protected $hidden = ['password_hash', 'password_salt', 'bio'];
|
protected $hidden = ['password_hash', 'password_salt', 'bio'];
|
||||||
|
|
||||||
public function avatar() {
|
public function avatar() {
|
||||||
return $this->hasOne('Entities\Image');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cover() {
|
|
||||||
return $this->belongsTo('Entities\Image');
|
return $this->belongsTo('Entities\Image');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +29,9 @@
|
||||||
return $this->email;
|
return $this->email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAvatarUrl($type = Cover::NORMAL) {
|
public function getAvatarUrl($type = Image::NORMAL) {
|
||||||
if (!$this->uses_gravatar)
|
if (!$this->uses_gravatar)
|
||||||
return $this->cover->getUrl();
|
return $this->avatar->getUrl();
|
||||||
|
|
||||||
$email = $this->gravatar;
|
$email = $this->gravatar;
|
||||||
if (!strlen($email))
|
if (!strlen($email))
|
||||||
|
@ -42,11 +40,11 @@
|
||||||
return Gravatar::getUrl($email, Image::$ImageTypes[$type]['width']);
|
return Gravatar::getUrl($email, Image::$ImageTypes[$type]['width']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAvatarFile($type = Cover::NORMAL) {
|
public function getAvatarFile($type = Image::NORMAL) {
|
||||||
if ($this->uses_gravatar)
|
if ($this->uses_gravatar)
|
||||||
return $this->user->getAvatar($type);
|
throw new Exception('Cannot get avatar file if this user is configured to use Gravatar!');
|
||||||
|
|
||||||
$cover = Cover::$Covers[$type];
|
$imageType = Image::$ImageTypes[$type];
|
||||||
return URL::to('t' . $this->id . '/cover_' . $cover['name'] . '.png?' . $this->cover_id);
|
return URL::to('t' . $this->id . '/cover_' . $imageType['name'] . '.png?' . $this->cover_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -50,9 +50,13 @@
|
||||||
Route::post('/playlists/create', 'Api\Web\PlaylistsController@postCreate');
|
Route::post('/playlists/create', 'Api\Web\PlaylistsController@postCreate');
|
||||||
Route::post('/playlists/delete/{id}', 'Api\Web\PlaylistsController@postDelete');
|
Route::post('/playlists/delete/{id}', 'Api\Web\PlaylistsController@postDelete');
|
||||||
Route::post('/playlists/edit/{id}', 'Api\Web\PlaylistsController@postEdit');
|
Route::post('/playlists/edit/{id}', 'Api\Web\PlaylistsController@postEdit');
|
||||||
|
|
||||||
|
Route::post('/account/settings/save', 'Api\Web\AccountController@postSave');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['before' => 'auth'], function() {
|
Route::group(['before' => 'auth'], function() {
|
||||||
|
Route::get('/account/settings', 'Api\Web\AccountController@getSettings');
|
||||||
|
|
||||||
Route::get('/images/owned', 'Api\Web\ImagesController@getOwned');
|
Route::get('/images/owned', 'Api\Web\ImagesController@getOwned');
|
||||||
|
|
||||||
Route::get('/tracks/owned', 'Api\Web\TracksController@getOwned');
|
Route::get('/tracks/owned', 'Api\Web\TracksController@getOwned');
|
||||||
|
|
|
@ -1,5 +1,63 @@
|
||||||
angular.module('ponyfm').controller "account-settings", [
|
angular.module('ponyfm').controller "account-settings", [
|
||||||
'$scope', 'auth'
|
'$scope', 'auth'
|
||||||
($scope, auth) ->
|
($scope, auth) ->
|
||||||
|
$scope.settings = {}
|
||||||
|
$scope.errors = {}
|
||||||
|
$scope.isDirty = false
|
||||||
|
|
||||||
|
$scope.touchModel = () ->
|
||||||
|
$scope.isDirty = true
|
||||||
|
|
||||||
|
$scope.refresh = () ->
|
||||||
|
$.getJSON('/api/web/account/settings')
|
||||||
|
.done (res) -> $scope.$apply ->
|
||||||
|
$scope.settings = res
|
||||||
|
|
||||||
|
$scope.setAvatar = (image, type) ->
|
||||||
|
delete $scope.settings.avatar_id
|
||||||
|
delete $scope.settings.avatar
|
||||||
|
|
||||||
|
if type == 'file'
|
||||||
|
$scope.settings.avatar = image
|
||||||
|
else if type == 'gallery'
|
||||||
|
$scope.settings.avatar_id = image.id
|
||||||
|
|
||||||
|
$scope.isDirty = true
|
||||||
|
|
||||||
|
$scope.updateAccount = () ->
|
||||||
|
return if !$scope.isDirty
|
||||||
|
|
||||||
|
xhr = new XMLHttpRequest()
|
||||||
|
xhr.onload = -> $scope.$apply ->
|
||||||
|
$scope.isSaving = false
|
||||||
|
response = $.parseJSON(xhr.responseText)
|
||||||
|
if xhr.status != 200
|
||||||
|
$scope.errors = {}
|
||||||
|
_.each response.errors, (value, key) -> $scope.errors[key] = value.join ', '
|
||||||
|
return
|
||||||
|
|
||||||
|
$scope.isDirty = false
|
||||||
|
$scope.errors = {}
|
||||||
|
$scope.refresh()
|
||||||
|
|
||||||
|
formData = new FormData()
|
||||||
|
|
||||||
|
_.each $scope.settings, (value, name) ->
|
||||||
|
if name == 'avatar'
|
||||||
|
return if value == null
|
||||||
|
if typeof(value) == 'object'
|
||||||
|
formData.append name, value, value.name
|
||||||
|
else
|
||||||
|
formData.append name, value
|
||||||
|
|
||||||
|
xhr.open 'POST', '/api/web/account/settings/save', true
|
||||||
|
xhr.setRequestHeader 'X-Token', pfm.token
|
||||||
|
$scope.isSaving = true
|
||||||
|
xhr.send formData
|
||||||
|
|
||||||
|
$scope.refresh()
|
||||||
|
|
||||||
|
$scope.$on '$stateChangeStart', (e) ->
|
||||||
|
return if $scope.selectedTrack == null || !$scope.isDirty
|
||||||
|
e.preventDefault() if !confirm('Are you sure you want to leave this page without saving your changes?')
|
||||||
]
|
]
|
|
@ -15,6 +15,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-settings-form {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
ul.playlists {
|
ul.playlists {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
|
|
@ -25,12 +25,12 @@ html body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-content-animate-enter {
|
.site-content-animate-enter {
|
||||||
opacity: 0;
|
|
||||||
.transition(all 400ms ease-out);
|
.transition(all 400ms ease-out);
|
||||||
|
.transform(translate(0, -100%));
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-content-animate-enter.site-content-animate-enter-active {
|
.site-content-animate-enter.site-content-animate-enter-active {
|
||||||
opacity: 1;
|
.transform(translate(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-content-animate-leave {
|
.site-content-animate-leave {
|
||||||
|
@ -39,8 +39,7 @@ html body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-content-animate-leave.site-content-animate-leave-active {
|
.site-content-animate-leave.site-content-animate-leave-active {
|
||||||
opacity: .5;
|
.transform(translate(0, 100%));
|
||||||
.transform(scale(.95));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
|
|
@ -1,3 +1,42 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Account Settings</h1>
|
<h1>Account Settings</h1>
|
||||||
|
<form ng-submit="updateAccount()" class="pfm-form account-settings-form">
|
||||||
|
<ul class="toolbar">
|
||||||
|
<li>
|
||||||
|
<button type="submit" class="btn" ng-class="{disabled: !isDirty || isSaving, 'btn-primary': isDirty}">
|
||||||
|
Save Changes
|
||||||
|
<i ng-show="isSaving" class="icon-cog icon-spin icon-large"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="stretch-to-bottom">
|
||||||
|
<div class="form-row" ng-class="{'has-error': errors.display_name != null}">
|
||||||
|
<label for="sync_names" class="strong"><input ng-disabled="isSaving" ng-change="touchModel();" id="sync_names" type="checkbox" ng-model="settings.sync_names" /> Sync my MLP Forums display name with Pony.fm</label>
|
||||||
|
<input type="text" ng-disabled="isSaving" ng-change="touchModel()" ng-show="!settings.sync_names" placeholder="Display Name" id="display_name" ng-model="settings.display_name" />
|
||||||
|
<div ng-show="settings.sync_names" class="alert alert-info">Your current MLP Forums display name is <strong>{{settings.mlpforums_name}}</strong></div>
|
||||||
|
<div class="error">{{errors.display_name}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row" ng-class="{'has-error': errors.bio != null}">
|
||||||
|
<label class="strong" for="bio">Bio</label>
|
||||||
|
<textarea id="bio" placeholder="bio (optional)" ng-model="settings.bio" ng-disabled="isLoading" ng-change="touchModel()"></textarea>
|
||||||
|
<div class="error">{{errors.description}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="form-row span6" ng-class="{'has-error': errors.avatar != null || errors.gravatar != null}">
|
||||||
|
<label for="uses_gravatar">
|
||||||
|
<input ng-change="touchModel()" ng-disabled="isLoading" id="uses_gravatar" type="checkbox" ng-model="settings.uses_gravatar" /> Use Gravatar
|
||||||
|
</label>
|
||||||
|
<div ng-show="!settings.uses_gravatar">
|
||||||
|
<pfm-image-upload set-image="setAvatar" image="settings.avatar_url" />
|
||||||
|
</div>
|
||||||
|
<input type="text" ng-disabled="isSaving" ng-change="touchModel()" ng-show="settings.uses_gravatar" placeholder="Gravatar Email" ng-model="settings.gravatar" />
|
||||||
|
<div class="error" ng-show="errors.avatar != null">{{errors.avatar}}</div>
|
||||||
|
<div class="error" ng-show="errors.gravatar != null">{{errors.gravatar}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row span6">
|
||||||
|
<label for="can_see_explicit_content"><input ng-change="touchModel()" ng-disabled="isLoading" id="can_see_explicit_content" type="checkbox" ng-model="settings.can_see_explicit_content" /> Can See Explicit Content</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
Loading…
Reference in a new issue