mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-12-22 13:03:16 +00:00
commit
cde0323401
6 changed files with 240 additions and 12 deletions
|
@ -83,6 +83,8 @@
|
||||||
- Update ApiV1Controller, fix pagination header. Fixes #3354 ([4fe07e6f](https://github.com/pixelfed/pixelfed/commit/4fe07e6f))
|
- Update ApiV1Controller, fix pagination header. Fixes #3354 ([4fe07e6f](https://github.com/pixelfed/pixelfed/commit/4fe07e6f))
|
||||||
- Update ApiV1Controller, add optional place_id parameter to POST /api/v1/statuses endpoint ([ef0d1f84](https://github.com/pixelfed/pixelfed/commit/ef0d1f84))
|
- Update ApiV1Controller, add optional place_id parameter to POST /api/v1/statuses endpoint ([ef0d1f84](https://github.com/pixelfed/pixelfed/commit/ef0d1f84))
|
||||||
- Update SettingsController, fix double json encoding and cache settings for 7 days ([4514ab1d](https://github.com/pixelfed/pixelfed/commit/4514ab1d))
|
- Update SettingsController, fix double json encoding and cache settings for 7 days ([4514ab1d](https://github.com/pixelfed/pixelfed/commit/4514ab1d))
|
||||||
|
- Update ApiV1Controller, fix mute/block entities ([364adb43](https://github.com/pixelfed/pixelfed/commit/364adb43))
|
||||||
|
- Update atom feed, remove invalid entities ([e362ef9e](https://github.com/pixelfed/pixelfed/commit/e362ef9e))
|
||||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||||
|
|
||||||
## [v0.11.3 (2022-05-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.2...v0.11.3)
|
## [v0.11.3 (2022-05-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.2...v0.11.3)
|
||||||
|
|
|
@ -888,6 +888,7 @@ class ApiV1Controller extends Controller
|
||||||
->whereUserId($user->profile_id)
|
->whereUserId($user->profile_id)
|
||||||
->whereFilterableType('App\Profile')
|
->whereFilterableType('App\Profile')
|
||||||
->whereFilterType('block')
|
->whereFilterType('block')
|
||||||
|
->orderByDesc('id')
|
||||||
->simplePaginate($limit)
|
->simplePaginate($limit)
|
||||||
->pluck('filterable_id')
|
->pluck('filterable_id')
|
||||||
->map(function($id) {
|
->map(function($id) {
|
||||||
|
@ -895,7 +896,8 @@ class ApiV1Controller extends Controller
|
||||||
})
|
})
|
||||||
->filter(function($account) {
|
->filter(function($account) {
|
||||||
return $account && isset($account['id']);
|
return $account && isset($account['id']);
|
||||||
});
|
})
|
||||||
|
->values();
|
||||||
|
|
||||||
return $this->json($blocked);
|
return $this->json($blocked);
|
||||||
}
|
}
|
||||||
|
@ -1750,6 +1752,7 @@ class ApiV1Controller extends Controller
|
||||||
$mutes = UserFilter::whereUserId($user->profile_id)
|
$mutes = UserFilter::whereUserId($user->profile_id)
|
||||||
->whereFilterableType('App\Profile')
|
->whereFilterableType('App\Profile')
|
||||||
->whereFilterType('mute')
|
->whereFilterType('mute')
|
||||||
|
->orderByDesc('id')
|
||||||
->simplePaginate($limit)
|
->simplePaginate($limit)
|
||||||
->pluck('filterable_id')
|
->pluck('filterable_id')
|
||||||
->map(function($id) {
|
->map(function($id) {
|
||||||
|
@ -1757,7 +1760,8 @@ class ApiV1Controller extends Controller
|
||||||
})
|
})
|
||||||
->filter(function($account) {
|
->filter(function($account) {
|
||||||
return $account && isset($account['id']);
|
return $account && isset($account['id']);
|
||||||
});
|
})
|
||||||
|
->values();
|
||||||
|
|
||||||
return $this->json($mutes);
|
return $this->json($mutes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,23 @@
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use Cache;
|
use Cache;
|
||||||
|
use DB;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use League\Fractal;
|
use League\Fractal;
|
||||||
use League\Fractal\Serializer\ArraySerializer;
|
use League\Fractal\Serializer\ArraySerializer;
|
||||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||||
|
use App\AccountLog;
|
||||||
|
use App\EmailVerification;
|
||||||
use App\Status;
|
use App\Status;
|
||||||
use App\Report;
|
use App\Report;
|
||||||
use App\Profile;
|
use App\Profile;
|
||||||
use App\Services\AccountService;
|
use App\Services\AccountService;
|
||||||
use App\Services\StatusService;
|
use App\Services\StatusService;
|
||||||
use App\Services\ProfileStatusService;
|
use App\Services\ProfileStatusService;
|
||||||
|
use Jenssegers\Agent\Agent;
|
||||||
|
use Mail;
|
||||||
|
use App\Mail\PasswordChange;
|
||||||
|
|
||||||
class ApiV1Dot1Controller extends Controller
|
class ApiV1Dot1Controller extends Controller
|
||||||
{
|
{
|
||||||
|
@ -204,4 +210,185 @@ class ApiV1Dot1Controller extends Controller
|
||||||
|
|
||||||
return $this->json($res);
|
return $this->json($res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/v1.1/accounts/change-password
|
||||||
|
*
|
||||||
|
* @return \App\Transformer\Api\AccountTransformer
|
||||||
|
*/
|
||||||
|
public function accountChangePassword(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(!$user, 403);
|
||||||
|
abort_if($user->status != null, 403);
|
||||||
|
|
||||||
|
$this->validate($request, [
|
||||||
|
'current_password' => 'bail|required|current_password',
|
||||||
|
'new_password' => 'required|min:' . config('pixelfed.min_password_length', 8),
|
||||||
|
'confirm_password' => 'required|same:new_password'
|
||||||
|
],[
|
||||||
|
'current_password' => 'The password you entered is incorrect'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->password = bcrypt($request->input('new_password'));
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$log = new AccountLog;
|
||||||
|
$log->user_id = $user->id;
|
||||||
|
$log->item_id = $user->id;
|
||||||
|
$log->item_type = 'App\User';
|
||||||
|
$log->action = 'account.edit.password';
|
||||||
|
$log->message = 'Password changed';
|
||||||
|
$log->link = null;
|
||||||
|
$log->ip_address = $request->ip();
|
||||||
|
$log->user_agent = $request->userAgent();
|
||||||
|
$log->save();
|
||||||
|
|
||||||
|
Mail::to($request->user())->send(new PasswordChange($user));
|
||||||
|
|
||||||
|
return $this->json(AccountService::get($user->profile_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/v1.1/accounts/login-activity
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function accountLoginActivity(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(!$user, 403);
|
||||||
|
abort_if($user->status != null, 403);
|
||||||
|
$agent = new Agent();
|
||||||
|
$currentIp = $request->ip();
|
||||||
|
|
||||||
|
$activity = AccountLog::whereUserId($user->id)
|
||||||
|
->whereAction('auth.login')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->groupBy('ip_address')
|
||||||
|
->limit(10)
|
||||||
|
->get()
|
||||||
|
->map(function($item) use($agent, $currentIp) {
|
||||||
|
$agent->setUserAgent($item->user_agent);
|
||||||
|
return [
|
||||||
|
'id' => $item->id,
|
||||||
|
'action' => $item->action,
|
||||||
|
'ip' => $item->ip_address,
|
||||||
|
'ip_current' => $item->ip_address === $currentIp,
|
||||||
|
'is_mobile' => $agent->isMobile(),
|
||||||
|
'device' => $agent->device(),
|
||||||
|
'browser' => $agent->browser(),
|
||||||
|
'platform' => $agent->platform(),
|
||||||
|
'created_at' => $item->created_at->format('c')
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->json($activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/v1.1/accounts/two-factor
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function accountTwoFactor(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(!$user, 403);
|
||||||
|
abort_if($user->status != null, 403);
|
||||||
|
|
||||||
|
$res = [
|
||||||
|
'active' => (bool) $user->{'2fa_enabled'},
|
||||||
|
'setup_at' => $user->{'2fa_setup_at'}
|
||||||
|
];
|
||||||
|
return $this->json($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/v1.1/accounts/emails-from-pixelfed
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function accountEmailsFromPixelfed(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(!$user, 403);
|
||||||
|
abort_if($user->status != null, 403);
|
||||||
|
|
||||||
|
$emailVerifications = EmailVerification::whereUserId($user->id)
|
||||||
|
->orderByDesc('id')
|
||||||
|
->where('created_at', '>', now()->subDays(14))
|
||||||
|
->limit(10)
|
||||||
|
->get()
|
||||||
|
->map(function($mail) {
|
||||||
|
return [
|
||||||
|
'type' => 'Email Verification',
|
||||||
|
'created_at' => $mail->created_at->format('c')
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$passwordResets = DB::table('password_resets')
|
||||||
|
->whereEmail($user->email)
|
||||||
|
->where('created_at', '>', now()->subDays(14))
|
||||||
|
->orderByDesc('created_at')
|
||||||
|
->limit(10)
|
||||||
|
->get()
|
||||||
|
->map(function($mail) {
|
||||||
|
return [
|
||||||
|
'type' => 'Password Reset',
|
||||||
|
'created_at' => now()->parse($mail->created_at)->format('c')
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$passwordChanges = AccountLog::whereUserId($user->id)
|
||||||
|
->whereAction('account.edit.password')
|
||||||
|
->where('created_at', '>', now()->subDays(14))
|
||||||
|
->orderByDesc('created_at')
|
||||||
|
->limit(10)
|
||||||
|
->get()
|
||||||
|
->map(function($mail) {
|
||||||
|
return [
|
||||||
|
'type' => 'Password Change',
|
||||||
|
'created_at' => $mail->created_at
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$res = [
|
||||||
|
'email_verifications' => $emailVerifications,
|
||||||
|
'password_resets' => $passwordResets,
|
||||||
|
'password_changes' => $passwordChanges
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->json($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/v1.1/accounts/apps-and-applications
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function accountApps(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(!$user, 403);
|
||||||
|
abort_if($user->status != null, 403);
|
||||||
|
|
||||||
|
$res = $user->tokens->map(function($token, $key) {
|
||||||
|
return [
|
||||||
|
'id' => $key + 1,
|
||||||
|
'did' => encrypt($token->id),
|
||||||
|
'name' => $token->name,
|
||||||
|
'scopes' => $token->scopes,
|
||||||
|
'revoked' => $token->revoked,
|
||||||
|
'created_at' => $token->created_at,
|
||||||
|
'expires_at' => $token->expires_at
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->json($res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,53 @@ use App\Like;
|
||||||
class LikeService {
|
class LikeService {
|
||||||
|
|
||||||
const CACHE_KEY = 'pf:services:likes:ids:';
|
const CACHE_KEY = 'pf:services:likes:ids:';
|
||||||
|
const CACHE_SET_KEY = 'pf:services:likes:set:';
|
||||||
|
|
||||||
public static function add($profileId, $statusId)
|
public static function add($profileId, $statusId)
|
||||||
{
|
{
|
||||||
$key = self::CACHE_KEY . $profileId . ':' . $statusId;
|
$key = self::CACHE_KEY . $profileId . ':' . $statusId;
|
||||||
Cache::increment('pf:services:likes:count:'.$statusId);
|
Cache::increment('pf:services:likes:count:'.$statusId);
|
||||||
Cache::forget('pf:services:likes:liked_by:'.$statusId);
|
Cache::forget('pf:services:likes:liked_by:'.$statusId);
|
||||||
|
self::setAdd($profileId, $statusId);
|
||||||
return Cache::put($key, true, 86400);
|
return Cache::put($key, true, 86400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function setAdd($profileId, $statusId)
|
||||||
|
{
|
||||||
|
if(self::setCount($profileId) > 400) {
|
||||||
|
if(config('database.redis.client') === 'phpredis') {
|
||||||
|
Redis::zpopmin(self::CACHE_SET_KEY . $id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redis::zadd(self::CACHE_SET_KEY . $profileId, $statusId, $statusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setCount($id)
|
||||||
|
{
|
||||||
|
return Redis::zcard(self::CACHE_SET_KEY . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setRem($profileId, $val)
|
||||||
|
{
|
||||||
|
return Redis::zrem(self::CACHE_SET_KEY . $profileId, $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($profileId, $start = 0, $stop = 10)
|
||||||
|
{
|
||||||
|
if($stop > 100) {
|
||||||
|
$stop = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redis::zrevrange(self::CACHE_SET_KEY . $profileId, $start, $stop);
|
||||||
|
}
|
||||||
|
|
||||||
public static function remove($profileId, $statusId)
|
public static function remove($profileId, $statusId)
|
||||||
{
|
{
|
||||||
$key = self::CACHE_KEY . $profileId . ':' . $statusId;
|
$key = self::CACHE_KEY . $profileId . ':' . $statusId;
|
||||||
Cache::decrement('pf:services:likes:count:'.$statusId);
|
Cache::decrement('pf:services:likes:count:'.$statusId);
|
||||||
Cache::forget('pf:services:likes:liked_by:'.$statusId);
|
Cache::forget('pf:services:likes:liked_by:'.$statusId);
|
||||||
|
self::setRem($profileId, $statusId);
|
||||||
return Cache::put($key, false, 86400);
|
return Cache::put($key, false, 86400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,20 +7,14 @@
|
||||||
<title>{{$profile['username']}} on Pixelfed</title>
|
<title>{{$profile['username']}} on Pixelfed</title>
|
||||||
<subtitle type="html">{{$profile['note']}}</subtitle>
|
<subtitle type="html">{{$profile['note']}}</subtitle>
|
||||||
<updated>{{$profile['created_at']}}</updated>
|
<updated>{{$profile['created_at']}}</updated>
|
||||||
<logo></logo>
|
|
||||||
<author>
|
<author>
|
||||||
<id>{{$profile['url']}}</id>
|
|
||||||
<uri>{{$profile['url']}}</uri>
|
<uri>{{$profile['url']}}</uri>
|
||||||
<name>{{$profile['url']}}</name>
|
<name>{{$profile['url']}}</name>
|
||||||
<summary type="html">{{$profile['note']}}</summary>
|
|
||||||
<link rel="alternate" type="text/html" href="{{$profile['url']}}"/>
|
|
||||||
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="{{$profile['avatar']}}"/>
|
|
||||||
</author>
|
</author>
|
||||||
<link rel="alternate" type="text/html" href="{{$profile['url']}}"/>
|
<link rel="alternate" type="text/html" href="{{$profile['url']}}"/>
|
||||||
<link rel="self" type="application/atom+xml" href="{{$permalink}}"/>
|
<link rel="self" type="application/atom+xml" href="{{$permalink}}"/>
|
||||||
@foreach($items as $item)
|
@foreach($items as $item) <entry>
|
||||||
<entry>
|
<title>{{ $item['content'] ? strip_tags($item['content']) : "No caption" }}</title>
|
||||||
<title>{{ strip_tags($item['content']) }}</title>
|
|
||||||
<link rel="alternate" href="{{ $item['url'] }}" />
|
<link rel="alternate" href="{{ $item['url'] }}" />
|
||||||
<id>{{ $item['url'] }}</id>
|
<id>{{ $item['url'] }}</id>
|
||||||
<author>
|
<author>
|
||||||
|
|
|
@ -99,8 +99,16 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
|
||||||
|
|
||||||
Route::group(['prefix' => 'v1.1'], function() use($middleware) {
|
Route::group(['prefix' => 'v1.1'], function() use($middleware) {
|
||||||
Route::post('report', 'Api\ApiV1Dot1Controller@report')->middleware($middleware);
|
Route::post('report', 'Api\ApiV1Dot1Controller@report')->middleware($middleware);
|
||||||
Route::delete('accounts/avatar', 'Api\ApiV1Dot1Controller@deleteAvatar')->middleware($middleware);
|
|
||||||
Route::get('accounts/{id}/posts', 'Api\ApiV1Dot1Controller@accountPosts')->middleware($middleware);
|
Route::group(['prefix' => 'accounts'], function () use($middleware) {
|
||||||
|
Route::delete('avatar', 'Api\ApiV1Dot1Controller@deleteAvatar')->middleware($middleware);
|
||||||
|
Route::get('{id}/posts', 'Api\ApiV1Dot1Controller@accountPosts')->middleware($middleware);
|
||||||
|
Route::post('change-password', 'Api\ApiV1Dot1Controller@accountChangePassword')->middleware($middleware);
|
||||||
|
Route::get('login-activity', 'Api\ApiV1Dot1Controller@accountLoginActivity')->middleware($middleware);
|
||||||
|
Route::get('two-factor', 'Api\ApiV1Dot1Controller@accountTwoFactor')->middleware($middleware);
|
||||||
|
Route::get('emails-from-pixelfed', 'Api\ApiV1Dot1Controller@accountEmailsFromPixelfed')->middleware($middleware);
|
||||||
|
Route::get('apps-and-applications', 'Api\ApiV1Dot1Controller@accountApps')->middleware($middleware);
|
||||||
|
});
|
||||||
|
|
||||||
Route::group(['prefix' => 'direct'], function () use($middleware) {
|
Route::group(['prefix' => 'direct'], function () use($middleware) {
|
||||||
Route::get('thread', 'DirectMessageController@thread')->middleware($middleware);
|
Route::get('thread', 'DirectMessageController@thread')->middleware($middleware);
|
||||||
|
|
Loading…
Reference in a new issue