Merge pull request #2690 from pixelfed/staging

Staging
This commit is contained in:
daniel 2021-03-01 00:31:29 -07:00 committed by GitHub
commit aad77239a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1290 additions and 816 deletions

View file

@ -49,6 +49,13 @@
- Updated MediaStorageService, improve head checks to fix failed jobs. ([1769cdfd](https://github.com/pixelfed/pixelfed/commit/1769cdfd))
- Updated user admin, remove expensive db query and add search. ([8feeadbf](https://github.com/pixelfed/pixelfed/commit/8feeadbf))
- Updated Compose apis, prevent private accounts from posting public or unlisted scopes. ([f53bfa6f](https://github.com/pixelfed/pixelfed/commit/f53bfa6f))
- Updated font icons, use font-display:swap. ([77d4353a](https://github.com/pixelfed/pixelfed/commit/77d4353a))
- Updated ComposeModal, limit visibility scope for private accounts. ([001d4105](https://github.com/pixelfed/pixelfed/commit/001d4105))
- Updated ComposeController, add autocomplete apis for hashtags and mentions. ([f0e48a09](https://github.com/pixelfed/pixelfed/commit/f0e48a09))
- Updated StatusController, invalidate profile embed cache on status delete. ([9c8a87c3](https://github.com/pixelfed/pixelfed/commit/9c8a87c3))
- Updated moderation api, invalidate profile embed. ([b2501bfc](https://github.com/pixelfed/pixelfed/commit/b2501bfc))
- Updated Nodeinfo util, use last_active_at for monthly active user count. ([d200c12c](https://github.com/pixelfed/pixelfed/commit/d200c12c))
- Updated PhotoPresenter, add width and height to images. ([3f8202e2](https://github.com/pixelfed/pixelfed/commit/3f8202e2))
- ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)

View file

@ -7,6 +7,7 @@ use Auth, Cache, Storage, URL;
use Carbon\Carbon;
use App\{
Avatar,
Hashtag,
Like,
Media,
MediaTag,
@ -304,6 +305,72 @@ class ComposeController extends Controller
return $places;
}
public function searchMentionAutocomplete(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'q' => 'required|string|min:2|max:50'
]);
$q = $request->input('q');
if(Str::of($q)->startsWith('@')) {
if(strlen($q) < 3) {
return [];
}
}
$blocked = UserFilter::whereFilterableType('App\Profile')
->whereFilterType('block')
->whereFilterableId($request->user()->profile_id)
->pluck('user_id');
$blocked->push($request->user()->profile_id);
$results = Profile::select('id','domain','username')
->whereNotIn('id', $blocked)
->where('username','like','%'.$q.'%')
->groupBy('domain')
->limit(15)
->get()
->map(function($profile) {
$username = $profile->domain ? substr($profile->username, 1) : $profile->username;
return [
'key' => '@' . str_limit($username, 30),
'value' => $username,
];
});
return $results;
}
public function searchHashtagAutocomplete(Request $request)
{
abort_if(!$request->user(), 403);
$this->validate($request, [
'q' => 'required|string|min:2|max:50'
]);
$q = $request->input('q');
$results = Hashtag::select('slug')
->where('slug', 'like', '%'.$q.'%')
->whereIsNsfw(false)
->whereIsBanned(false)
->limit(5)
->get()
->map(function($tag) {
return [
'key' => '#' . $tag->slug,
'value' => $tag->slug
];
});
return $results;
}
public function store(Request $request)
{
$this->validate($request, [

View file

@ -132,13 +132,15 @@ class InternalApiController extends Controller
public function statusReplies(Request $request, int $id)
{
$this->validate($request, [
'limit' => 'nullable|int|min:1|max:6'
]);
$parent = Status::whereScope('public')->findOrFail($id);
$limit = $request->input('limit') ?? 3;
$children = Status::whereInReplyToId($parent->id)
->orderBy('created_at', 'desc')
->take(3)
->take($limit)
->get();
$resource = new Fractal\Resource\Collection($children, new StatusTransformer());
$res = $this->fractal->createData($resource)->toArray();
@ -310,6 +312,10 @@ class InternalApiController extends Controller
}
break;
}
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
Cache::forget('profile:embed:' . $status->profile_id);
return ['msg' => 200];
}

View file

@ -166,7 +166,7 @@ class PublicApiController extends Controller
->whereNull('reblog_of_id')
->whereIn('scope', $scope)
->whereNotIn('profile_id', $filtered)
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->where('id', '>=', $request->min_id)
->orderBy('id', 'desc')
->paginate($limit);
@ -176,7 +176,7 @@ class PublicApiController extends Controller
->whereNull('reblog_of_id')
->whereIn('scope', $scope)
->whereNotIn('profile_id', $filtered)
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->where('id', '<=', $request->max_id)
->orderBy('id', 'desc')
->paginate($limit);
@ -186,7 +186,7 @@ class PublicApiController extends Controller
->whereNull('reblog_of_id')
->whereIn('scope', $scope)
->whereNotIn('profile_id', $filtered)
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
->orderBy('id', 'desc')
->paginate($limit);
}

View file

@ -74,6 +74,12 @@ class StatusController extends Controller
}
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
// $template = $status->type === 'video' &&
// $request->has('video_beta') &&
// $request->video_beta == 1 &&
// $request->user() ?
// 'status.show_video' : 'status.show';
return view($template, compact('user', 'status'));
}
@ -212,6 +218,7 @@ class StatusController extends Controller
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
Cache::forget('profile:status_count:' . $status->profile_id);
Cache::forget('profile:embed:' . $status->profile_id);
StatusService::del($status->id);
if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
Cache::forget('profile:status_count:'.$status->profile_id);

View file

@ -12,24 +12,31 @@ class Nodeinfo {
{
$res = Cache::remember('api:nodeinfo', now()->addMinutes(15), function () {
$activeHalfYear = Cache::remember('api:nodeinfo:ahy', now()->addHours(12), function() {
// todo: replace with last_active_at after July 9, 2021 (96afc3e781)
$count = collect([]);
$likes = Like::select('profile_id')->with('actor')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray();
$count = $count->merge($likes);
$statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray();
$count = $count->merge($statuses);
$profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('id')->pluck('id')->toArray();
$profiles = User::select('profile_id', 'last_active_at')
->whereNotNull('last_active_at')
->where('last_active_at', '>', now()->subMonths(6))
->pluck('profile_id')
->toArray();
$newProfiles = User::select('profile_id', 'last_active_at', 'created_at')
->whereNull('last_active_at')
->where('created_at', '>', now()->subMonths(6))
->pluck('profile_id')
->toArray();
$count = $count->merge($newProfiles);
$count = $count->merge($profiles);
return $count->unique()->count();
});
$activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(12), function() {
$count = collect([]);
$likes = Like::select('profile_id')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray();
$count = $count->merge($likes);
$statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray();
$count = $count->merge($statuses);
$profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('id')->pluck('id')->toArray();
$count = $count->merge($profiles);
return $count->unique()->count();
$activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(2), function() {
return User::select('last_active_at')
->where('last_active_at', '>', now()->subMonths(1))
->orWhere('created_at', '>', now()->subMonths(1))
->count();
});
return [
'metadata' => [

BIN
public/css/app.css vendored

Binary file not shown.

BIN
public/css/appdark.css vendored

Binary file not shown.

BIN
public/css/landing.css vendored

Binary file not shown.

BIN
public/css/quill.css vendored

Binary file not shown.

BIN
public/js/compose.js vendored

Binary file not shown.

BIN
public/js/profile.js vendored

Binary file not shown.

BIN
public/js/rempos.js vendored

Binary file not shown.

BIN
public/js/status.js vendored

Binary file not shown.

BIN
public/js/timeline.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -479,9 +479,26 @@
<div v-if="page == 'visibility'" class="w-100 h-100">
<div class="list-group list-group-flush">
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'public'?'text-primary':'']" @click="toggleVisibility('public')">Public</div>
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'unlisted'?'text-primary':'']" @click="toggleVisibility('unlisted')">Unlisted</div>
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'private'?'text-primary':'']" @click="toggleVisibility('private')">Followers Only</div>
<div
v-if="!profile.locked"
class="list-group-item lead cursor-pointer"
:class="{ 'text-primary': visibility == 'public' }"
@click="toggleVisibility('public')">
Public
</div>
<div
v-if="!profile.locked"
class="list-group-item lead cursor-pointer"
:class="{ 'text-primary': visibility == 'unlisted' }"
@click="toggleVisibility('unlisted')">
Unlisted
</div>
<div
class="list-group-item lead cursor-pointer"
:class="{ 'text-primary': visibility == 'private' }"
@click="toggleVisibility('private')">
Followers Only
</div>
</div>
</div>
@ -641,7 +658,7 @@ export default {
return {
config: window.App.config,
pageLoading: false,
profile: {},
profile: window._sharedData.curUser,
composeText: '',
composeTextLength: 0,
nsfw: false,
@ -708,20 +725,19 @@ export default {
methods: {
fetchProfile() {
let self = this;
if(window._sharedData.curUser) {
self.profile = window._sharedData.curUser;
if(self.profile.locked == true) {
self.visibility = 'private';
self.visibilityTag = 'Followers Only';
if(window._sharedData.curUser.id) {
this.profile = window._sharedData.curUser;
if(this.profile.locked == true) {
this.visibility = 'private';
this.visibilityTag = 'Followers Only';
}
} else {
axios.get('/api/pixelfed/v1/accounts/verify_credentials').then(res => {
self.profile = res.data;
window.pixelfed.currentUser = res.data;
if(res.data.locked == true) {
self.visibility = 'private';
self.visibilityTag = 'Followers Only';
window._sharedData.currentUser = res.data;
this.profile = res.data;
if(this.profile.locked == true) {
this.visibility = 'private';
this.visibilityTag = 'Followers Only';
}
}).catch(err => {
});

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,13 @@
</div>
<div v-else>
<div :title="status.media_attachments[0].description">
<img :class="status.media_attachments[0].filter_class + ' card-img-top'" :src="status.media_attachments[0].url" loading="lazy" :alt="altText(status)" onerror="this.onerror=null;this.src='/storage/no-preview.png'">
<img class="card-img-top"
:src="status.media_attachments[0].url"
loading="lazy"
:alt="altText(status)"
:width="width()"
:height="height()"
onerror="this.onerror=null;this.src='/storage/no-preview.png'">
</div>
</div>
</template>
@ -67,6 +73,24 @@
toggleContentWarning(status) {
this.$emit('togglecw');
},
width() {
if( !this.status.media_attachments[0].meta ||
!this.status.media_attachments[0].meta.original ||
!this.status.media_attachments[0].meta.original.width ) {
return;
}
return this.status.media_attachments[0].meta.original.width;
},
height() {
if( !this.status.media_attachments[0].meta ||
!this.status.media_attachments[0].meta.original ||
!this.status.media_attachments[0].meta.original.height ) {
return;
}
return this.status.media_attachments[0].meta.original.height;
}
}
}

View file

@ -4255,7 +4255,7 @@ readers do not read off random characters that represent icons */
font-family: 'Font Awesome 5 Brands';
font-style: normal;
font-weight: normal;
font-display: auto;
font-display: swap;
src: url("/fonts/fa-brands-400.eot");
src: url("/fonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-brands-400.woff2") format("woff2"), url("/fonts/fa-brands-400.woff") format("woff"), url("/fonts/fa-brands-400.ttf") format("truetype"), url("/fonts/fa-brands-400.svg#fontawesome") format("svg"); }
@ -4265,7 +4265,7 @@ readers do not read off random characters that represent icons */
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 400;
font-display: auto;
font-display: swap;
src: url("/fonts/fa-regular-400.eot");
src: url("/fonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-regular-400.woff2") format("woff2"), url("/fonts/fa-regular-400.woff") format("woff"), url("/fonts/fa-regular-400.ttf") format("truetype"), url("/fonts/fa-regular-400.svg#fontawesome") format("svg"); }
@ -4276,7 +4276,7 @@ readers do not read off random characters that represent icons */
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 900;
font-display: auto;
font-display: swap;
src: url("/fonts/fa-solid-900.eot");
src: url("/fonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-solid-900.woff2") format("woff2"), url("/fonts/fa-solid-900.woff") format("woff"), url("/fonts/fa-solid-900.ttf") format("truetype"), url("/fonts/fa-solid-900.svg#fontawesome") format("svg"); }

View file

@ -113,6 +113,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::delete('/media/delete', 'ComposeController@mediaDelete');
Route::get('/search/tag', 'ComposeController@searchTag');
Route::get('/search/location', 'ComposeController@searchLocation');
Route::get('/search/mention', 'ComposeController@searchMentionAutocomplete');
Route::get('/search/hashtag', 'ComposeController@searchHashtagAutocomplete');
Route::post('/publish', 'ComposeController@store')
->middleware('throttle:maxPostsPerHour,60')