Merge pull request #5032 from pixelfed/staging

Staging
This commit is contained in:
daniel 2024-04-06 02:56:48 -06:00 committed by GitHub
commit 57df06a0b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
59 changed files with 1970 additions and 1802 deletions

View file

@ -19,6 +19,49 @@
- Update SiteController, add curatedOnboarding method that gracefully falls back to open registration when applicable ([95199843](https://github.com/pixelfed/pixelfed/commit/95199843)) - Update SiteController, add curatedOnboarding method that gracefully falls back to open registration when applicable ([95199843](https://github.com/pixelfed/pixelfed/commit/95199843))
- Update AP transformers, add DeleteActor activity ([bcce1df6](https://github.com/pixelfed/pixelfed/commit/bcce1df6)) - Update AP transformers, add DeleteActor activity ([bcce1df6](https://github.com/pixelfed/pixelfed/commit/bcce1df6))
- Update commands, add user account delete cli command to federate account deletion ([4aa0e25f](https://github.com/pixelfed/pixelfed/commit/4aa0e25f)) - Update commands, add user account delete cli command to federate account deletion ([4aa0e25f](https://github.com/pixelfed/pixelfed/commit/4aa0e25f))
- Update web-api popular accounts route to its own method to remove the breaking oauth scope bug ([a4bc5ce3](https://github.com/pixelfed/pixelfed/commit/a4bc5ce3))
- Update config cache ([5e4d4eff](https://github.com/pixelfed/pixelfed/commit/5e4d4eff))
- Update Config, use config_cache ([7785a2da](https://github.com/pixelfed/pixelfed/commit/7785a2da))
- Update ApiV1Dot1Controller, use config_cache for in-app registration ([b0cb4456](https://github.com/pixelfed/pixelfed/commit/b0cb4456))
- Update captcha, use config_cache helper ([8a89e3c9](https://github.com/pixelfed/pixelfed/commit/8a89e3c9))
- Update custom emoji, add config_cache support ([481314cd](https://github.com/pixelfed/pixelfed/commit/481314cd))
- Update ProfileController, fix permalink redirect bug ([75081e60](https://github.com/pixelfed/pixelfed/commit/75081e60))
- Update admin css, use font-display:swap for nucleo icons ([8a0c456e](https://github.com/pixelfed/pixelfed/commit/8a0c456e))
- Update PixelfedDirectoryController, fix boolean cast bug ([f08aab22](https://github.com/pixelfed/pixelfed/commit/f08aab22))
- Update PixelfedDirectoryController, use cached stats ([f2f2a809](https://github.com/pixelfed/pixelfed/commit/f2f2a809))
- Update AdminDirectoryController, fix type casting ([ad506e90](https://github.com/pixelfed/pixelfed/commit/ad506e90))
- Update image pipeline, use config_cache ([a72188a7](https://github.com/pixelfed/pixelfed/commit/a72188a7))
- Update cloud storage, use config_cache ([665581d8](https://github.com/pixelfed/pixelfed/commit/665581d8))
- Update pixelfed.max_album_length, use config_cache ([fecbe189](https://github.com/pixelfed/pixelfed/commit/fecbe189))
- Update media_types, use config_cache ([d670de17](https://github.com/pixelfed/pixelfed/commit/d670de17))
- Update landing settings, use config_cache ([40478f25](https://github.com/pixelfed/pixelfed/commit/40478f25))
- Update activitypub setting, use config_cache ([5071aaf4](https://github.com/pixelfed/pixelfed/commit/5071aaf4))
- Update oauth setting, use config_cache ([ce228f7f](https://github.com/pixelfed/pixelfed/commit/ce228f7f))
- Update stories config, use config_cache ([d1adb109](https://github.com/pixelfed/pixelfed/commit/d1adb109))
- Update ig import, use config_cache ([da0e0ffa](https://github.com/pixelfed/pixelfed/commit/da0e0ffa))
- Update autospam config, use config_cache ([a76cb5f4](https://github.com/pixelfed/pixelfed/commit/a76cb5f4))
- Update app.name config, use config_cache ([911446c0](https://github.com/pixelfed/pixelfed/commit/911446c0))
- Update UserObserver, fix type casting ([949e9979](https://github.com/pixelfed/pixelfed/commit/949e9979))
- Update user_filters, use config_cache ([6ce513f8](https://github.com/pixelfed/pixelfed/commit/6ce513f8))
- Update filesystems config, add to config_cache ([087b2791](https://github.com/pixelfed/pixelfed/commit/087b2791))
- Update web-admin routes, add setting api routes ([828a456f](https://github.com/pixelfed/pixelfed/commit/828a456f))
- Update hashtag component ([cee979ed](https://github.com/pixelfed/pixelfed/commit/cee979ed))
- Update AdminReadMore component, add .prevent to click action ([704e7b12](https://github.com/pixelfed/pixelfed/commit/704e7b12))
- Update admin dashboard, add admin settings partials ([eb487123](https://github.com/pixelfed/pixelfed/commit/eb487123))
- Update admin settings, refactor to vue component ([674e560f](https://github.com/pixelfed/pixelfed/commit/674e560f))
- Update ConfigCacheService, encrypt keys at rest ([3628b462](https://github.com/pixelfed/pixelfed/commit/3628b462))
- Update RemoteFollowImportRecent, use MediaPathService ([5162c070](https://github.com/pixelfed/pixelfed/commit/5162c070))
- Update AdminSettingsController, add user filter max limit settings ([ac1f0748](https://github.com/pixelfed/pixelfed/commit/ac1f0748))
- Update AdminSettingsController, add AdminSettingsService ([dcc5f416](https://github.com/pixelfed/pixelfed/commit/dcc5f416))
- Update AdminSettings component, fix user settings ([aba1e13d](https://github.com/pixelfed/pixelfed/commit/aba1e13d))
- Update AdminInstances component ([ec2fdd61](https://github.com/pixelfed/pixelfed/commit/ec2fdd61))
- Update AdminSettings, add max_account_size support ([2dcbc1d5](https://github.com/pixelfed/pixelfed/commit/2dcbc1d5))
- Update AdminSettings, use better validation for user integer settings ([d946afcc](https://github.com/pixelfed/pixelfed/commit/d946afcc))
- Update spa sass, fix timestamp dark mode bug ([4147f7c5](https://github.com/pixelfed/pixelfed/commit/4147f7c5))
- Update relationships view, fix unfollow hashtag bug. Fixes #5008 ([8c693640](https://github.com/pixelfed/pixelfed/commit/8c693640))
- Update PrivacySettings controller, refresh RelationshipService when unmute/unblocking ([b7322b68](https://github.com/pixelfed/pixelfed/commit/b7322b68))
- Update ApiV1Controller, improve refresh relations logic when (un)muting or (un)blocking ([b8e96a5f](https://github.com/pixelfed/pixelfed/commit/b8e96a5f))
- Update context menu, add mute/block/unfollow actions and update relationship store accordingly ([81d1e0fd](https://github.com/pixelfed/pixelfed/commit/81d1e0fd))
- ([](https://github.com/pixelfed/pixelfed/commit/)) - ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.13 (2024-03-05)](https://github.com/pixelfed/pixelfed/compare/v0.11.12...v0.11.13) ## [v0.11.13 (2024-03-05)](https://github.com/pixelfed/pixelfed/compare/v0.11.12...v0.11.13)

View file

@ -1200,8 +1200,8 @@ class ApiV1Controller extends Controller
if ($filter) { if ($filter) {
$filter->delete(); $filter->delete();
UserFilterService::unblock($pid, $profile->id); UserFilterService::unblock($pid, $profile->id);
RelationshipService::refresh($pid, $id);
} }
RelationshipService::refresh($pid, $id);
$resource = new Fractal\Resource\Item($profile, new RelationshipTransformer()); $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray(); $res = $this->fractal->createData($resource)->toArray();
@ -2207,9 +2207,10 @@ class ApiV1Controller extends Controller
if ($filter) { if ($filter) {
$filter->delete(); $filter->delete();
UserFilterService::unmute($pid, $profile->id); UserFilterService::unmute($pid, $profile->id);
RelationshipService::refresh($pid, $id);
} }
RelationshipService::refresh($pid, $id);
$resource = new Fractal\Resource\Item($profile, new RelationshipTransformer()); $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray(); $res = $this->fractal->createData($resource)->toArray();

View file

@ -2,23 +2,17 @@
namespace App\Http\Controllers\Settings; namespace App\Http\Controllers\Settings;
use App\AccountLog;
use App\EmailVerification;
use App\Instance;
use App\Follower; use App\Follower;
use App\Media;
use App\Profile; use App\Profile;
use App\User; use App\Services\RelationshipService;
use App\UserFilter; use App\UserFilter;
use App\Util\Lexer\PrettyNumber; use Auth;
use App\Util\ActivityPub\Helpers; use Cache;
use Auth, Cache, DB; use DB;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\UserDomainBlock;
trait PrivacySettings trait PrivacySettings
{ {
public function privacy() public function privacy()
{ {
$user = Auth::user(); $user = Auth::user();
@ -85,18 +79,19 @@ trait PrivacySettings
$settings->save(); $settings->save();
} }
$pid = $profile->id; $pid = $profile->id;
Cache::forget('profile:settings:' . $pid); Cache::forget('profile:settings:'.$pid);
Cache::forget('user:account:id:' . $profile->user_id); Cache::forget('user:account:id:'.$profile->user_id);
Cache::forget('profile:follower_count:' . $pid); Cache::forget('profile:follower_count:'.$pid);
Cache::forget('profile:following_count:' . $pid); Cache::forget('profile:following_count:'.$pid);
Cache::forget('profile:atom:enabled:' . $pid); Cache::forget('profile:atom:enabled:'.$pid);
Cache::forget('profile:embed:' . $pid); Cache::forget('profile:embed:'.$pid);
Cache::forget('pf:acct:settings:hidden-followers:' . $pid); Cache::forget('pf:acct:settings:hidden-followers:'.$pid);
Cache::forget('pf:acct:settings:hidden-following:' . $pid); Cache::forget('pf:acct:settings:hidden-following:'.$pid);
Cache::forget('pf:acct-trans:hideFollowing:' . $pid); Cache::forget('pf:acct-trans:hideFollowing:'.$pid);
Cache::forget('pf:acct-trans:hideFollowers:' . $pid); Cache::forget('pf:acct-trans:hideFollowers:'.$pid);
Cache::forget('pfc:cached-user:wt:' . strtolower($profile->username)); Cache::forget('pfc:cached-user:wt:'.strtolower($profile->username));
Cache::forget('pfc:cached-user:wot:' . strtolower($profile->username)); Cache::forget('pfc:cached-user:wot:'.strtolower($profile->username));
return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!'); return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
} }
@ -105,13 +100,14 @@ trait PrivacySettings
$pid = Auth::user()->profile->id; $pid = Auth::user()->profile->id;
$ids = (new UserFilter())->mutedUserIds($pid); $ids = (new UserFilter())->mutedUserIds($pid);
$users = Profile::whereIn('id', $ids)->simplePaginate(15); $users = Profile::whereIn('id', $ids)->simplePaginate(15);
return view('settings.privacy.muted', compact('users')); return view('settings.privacy.muted', compact('users'));
} }
public function mutedUsersUpdate(Request $request) public function mutedUsersUpdate(Request $request)
{ {
$this->validate($request, [ $this->validate($request, [
'profile_id' => 'required|integer|min:1' 'profile_id' => 'required|integer|min:1',
]); ]);
$fid = $request->input('profile_id'); $fid = $request->input('profile_id');
$pid = Auth::user()->profile->id; $pid = Auth::user()->profile->id;
@ -123,6 +119,8 @@ trait PrivacySettings
->firstOrFail(); ->firstOrFail();
$filter->delete(); $filter->delete();
}); });
RelationshipService::refresh($pid, $fid);
return redirect()->back(); return redirect()->back();
} }
@ -131,14 +129,14 @@ trait PrivacySettings
$pid = Auth::user()->profile->id; $pid = Auth::user()->profile->id;
$ids = (new UserFilter())->blockedUserIds($pid); $ids = (new UserFilter())->blockedUserIds($pid);
$users = Profile::whereIn('id', $ids)->simplePaginate(15); $users = Profile::whereIn('id', $ids)->simplePaginate(15);
return view('settings.privacy.blocked', compact('users')); return view('settings.privacy.blocked', compact('users'));
} }
public function blockedUsersUpdate(Request $request) public function blockedUsersUpdate(Request $request)
{ {
$this->validate($request, [ $this->validate($request, [
'profile_id' => 'required|integer|min:1' 'profile_id' => 'required|integer|min:1',
]); ]);
$fid = $request->input('profile_id'); $fid = $request->input('profile_id');
$pid = Auth::user()->profile->id; $pid = Auth::user()->profile->id;
@ -150,6 +148,8 @@ trait PrivacySettings
->firstOrFail(); ->firstOrFail();
$filter->delete(); $filter->delete();
}); });
RelationshipService::refresh($pid, $fid);
return redirect()->back(); return redirect()->back();
} }
@ -194,7 +194,7 @@ trait PrivacySettings
$profile = Auth::user()->profile; $profile = Auth::user()->profile;
$settings = Auth::user()->settings; $settings = Auth::user()->settings;
if($mode !== 'keep-all') { if ($mode !== 'keep-all') {
switch ($mode) { switch ($mode) {
case 'mutual-only': case 'mutual-only':
$following = $profile->following()->pluck('profiles.id'); $following = $profile->following()->pluck('profiles.id');
@ -211,7 +211,7 @@ trait PrivacySettings
break; break;
default: default:
# code... // code...
break; break;
} }
} }
@ -221,6 +221,7 @@ trait PrivacySettings
$settings->save(); $settings->save();
$profile->save(); $profile->save();
Cache::forget('profiles:private'); Cache::forget('profiles:private');
return [200]; return [200];
} }
} }

590
composer.lock generated

File diff suppressed because it is too large Load diff

1381
package-lock.json generated

File diff suppressed because it is too large Load diff

BIN
public/css/spa.css vendored

Binary file not shown.

Binary file not shown.

BIN
public/js/admin.js vendored

Binary file not shown.

BIN
public/js/app.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/daci.chunk.a498fff65c83f174.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/dms.chunk.a42edfd973f6c593.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/home.chunk.ccbe0267817f9a26.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/landing.js vendored

Binary file not shown.

BIN
public/js/manifest.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/portfolio.js vendored

Binary file not shown.

BIN
public/js/post.chunk.41ea9082b932e599.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/spa.js vendored

Binary file not shown.

BIN
public/js/vendor.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -10,79 +10,136 @@
body-class="list-group-flush p-0 rounded"> body-class="list-group-flush p-0 rounded">
<div class="list-group text-center"> <div class="list-group text-center">
<div <div v-if="status.visibility !== 'archived'" class="list-group-item d-flex p-0 m-0">
v-if="status.visibility !== 'archived'" <div class="border-right p-2 w-50">
class="list-group-item rounded cursor-pointer font-weight-bold" <a
@click="ctxMenuGoToPost()"> v-if="status"
{{ $t('menu.viewPost') }} class="menu-option"
:href="status.url"
@click.prevent="ctxMenuGoToPost()">
<div class="action-icon-link">
<div class="icon"><i class="fal fa-images fa-lg"></i></div>
<p class="mb-0">{{ $t('menu.viewPost') }}</p>
</div>
</a>
</div> </div>
<div <div class="p-2 flex-grow-1">
v-if="status.visibility !== 'archived'" <a
class="list-group-item rounded cursor-pointer font-weight-bold" v-if="status"
@click="ctxMenuGoToProfile()"> class="menu-option"
{{ $t('menu.viewProfile') }} :href="status.account.url"
@click.prevent="ctxMenuGoToProfile()">
<div class="action-icon-link">
<div class="icon"><i class="fal fa-user fa-lg"></i></div>
<p class="mb-0">{{ $t('menu.viewProfile') }}</p>
</div>
</a>
</div>
</div> </div>
<div <template v-if="ctxMenuRelationship">
<a
v-if="ctxMenuRelationship.following"
class="list-group-item menu-option text-danger"
href="#"
@click.prevent="handleUnfollow">
{{ $t('profile.unfollow') }}
</a>
<div v-else class="d-flex">
<div class="p-3 border-right w-50 text-center">
<a
class="small menu-option text-muted"
href="#"
@click.prevent="handleMute">
<div class="action-icon-link-inline">
<div class="icon"><i class="far" :class="[ ctxMenuRelationship.muting ? 'fa-eye' : 'fa-eye-slash' ]"></i></div>
<p class="text-muted mb-0">{{ ctxMenuRelationship.muting ? 'Unmute' : 'Mute' }}</p>
</div>
</a>
</div>
<div class="p-3 w-50">
<a
class="small menu-option text-danger"
href="#"
@click.prevent="handleBlock">
<div class="action-icon-link-inline">
<div class="icon"><i class="far fa-shield-alt"></i></div>
<p class="text-danger mb-0">Block</p>
</div>
</a>
</div>
</div>
</template>
<a
v-if="status.visibility !== 'archived'" v-if="status.visibility !== 'archived'"
class="list-group-item rounded cursor-pointer font-weight-bold" class="list-group-item menu-option"
@click="ctxMenuShare()"> href="#"
@click.prevent="ctxMenuShare()">
{{ $t('common.share') }} {{ $t('common.share') }}
</div> </a>
<div <a
v-if="status && profile && profile.is_admin == true && status.visibility !== 'archived'" v-if="status && profile && profile.is_admin == true && status.visibility !== 'archived'"
class="list-group-item rounded cursor-pointer font-weight-bold" class="list-group-item menu-option"
@click="ctxModMenuShow()"> href="#"
@click.prevent="ctxModMenuShow()">
{{ $t('menu.moderationTools') }} {{ $t('menu.moderationTools') }}
</div> </a>
<div <a
v-if="status && status.account.id != profile.id" v-if="status && status.account.id != profile.id"
class="list-group-item rounded cursor-pointer text-danger font-weight-bold" class="list-group-item menu-option text-danger"
@click="ctxMenuReportPost()"> href="#"
@click.prevent="ctxMenuReportPost()">
{{ $t('menu.report') }} {{ $t('menu.report') }}
</div> </a>
<div <a
v-if="status && profile.id == status.account.id && status.visibility !== 'archived'" v-if="status && profile.id == status.account.id && status.visibility !== 'archived'"
class="list-group-item rounded cursor-pointer text-danger font-weight-bold" class="list-group-item menu-option text-danger"
@click="archivePost(status)"> href="#"
@click.prevent="archivePost(status)">
{{ $t('menu.archive') }} {{ $t('menu.archive') }}
</div> </a>
<div <a
v-if="status && profile.id == status.account.id && status.visibility == 'archived'" v-if="status && profile.id == status.account.id && status.visibility == 'archived'"
class="list-group-item rounded cursor-pointer text-danger font-weight-bold" class="list-group-item menu-option text-danger"
@click="unarchivePost(status)"> href="#"
@click.prevent="unarchivePost(status)">
{{ $t('menu.unarchive') }} {{ $t('menu.unarchive') }}
</div> </a>
<div <a
v-if="config.ab.pue && status && profile.id == status.account.id && status.visibility !== 'archived'" v-if="config.ab.pue && status && profile.id == status.account.id && status.visibility !== 'archived'"
class="list-group-item rounded cursor-pointer text-danger font-weight-bold" class="list-group-item menu-option text-danger"
@click="editPost(status)"> href="#"
@click.prevent="editPost(status)">
Edit Edit
</div> </a>
<div <a
v-if="status && (profile.is_admin || profile.id == status.account.id) && status.visibility !== 'archived'" v-if="status && (profile.is_admin || profile.id == status.account.id) && status.visibility !== 'archived'"
class="list-group-item rounded cursor-pointer text-danger font-weight-bold" class="list-group-item menu-option text-danger"
@click="deletePost(status)"> href="#"
@click.prevent="deletePost(status)">
<div v-if="isDeleting" class="spinner-border spinner-border-sm" role="status"> <div v-if="isDeleting" class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span> <span class="sr-only">Loading...</span>
</div> </div>
<div v-else> <div v-else>
{{ $t('common.delete') }} {{ $t('common.delete') }}
</div> </div>
</div> </a>
<div <a
class="list-group-item rounded cursor-pointer text-lighter font-weight-bold" class="list-group-item menu-option text-lighter"
@click="closeCtxMenu()"> href="#"
@click.prevent="closeCtxMenu()">
{{ $t('common.cancel') }} {{ $t('common.cancel') }}
</div> </a>
</div> </div>
</b-modal> </b-modal>
@ -98,7 +155,7 @@
<div class="list-group text-center"> <div class="list-group text-center">
<p class="py-2 px-3 mb-0"> <p class="py-2 px-3 mb-0">
<div <div
class="text-center font-weight-bold text-danger"> class="text-center menu-option text-danger">
{{ $t('menu.moderationTools') }} {{ $t('menu.moderationTools') }}
</div> </div>
@ -107,38 +164,43 @@
</div> </div>
</p> </p>
<div <a
class="list-group-item rounded cursor-pointer" class="list-group-item menu-option"
@click="moderatePost(status, 'unlist')"> href="#"
@click.prevent="moderatePost(status, 'unlist')">
{{ $t('menu.unlistFromTimelines') }} {{ $t('menu.unlistFromTimelines') }}
</div> </a>
<div <a
v-if="status.sensitive" v-if="status.sensitive"
class="list-group-item rounded cursor-pointer" class="list-group-item menu-option"
@click="moderatePost(status, 'remcw')"> href="#"
@click.prevent="moderatePost(status, 'remcw')">
{{ $t('menu.removeCW') }} {{ $t('menu.removeCW') }}
</div> </a>
<div <a
v-else v-else
class="list-group-item rounded cursor-pointer" class="list-group-item menu-option"
@click="moderatePost(status, 'addcw')"> href="#"
@click.prevent="moderatePost(status, 'addcw')">
{{ $t('menu.addCW') }} {{ $t('menu.addCW') }}
</div> </a>
<div <a
class="list-group-item rounded cursor-pointer" class="list-group-item menu-option"
@click="moderatePost(status, 'spammer')"> href="#"
@click.prevent="moderatePost(status, 'spammer')">
{{ $t('menu.markAsSpammer') }}<br /> {{ $t('menu.markAsSpammer') }}<br />
<span class="small">{{ $t('menu.markAsSpammerText') }}</span> <span class="small">{{ $t('menu.markAsSpammerText') }}</span>
</div> </a>
<div <a
class="list-group-item rounded cursor-pointer text-lighter" class="list-group-item menu-option text-lighter"
@click="ctxModMenuClose()"> href="#"
@click.prevent="ctxModMenuClose()">
{{ $t('common.cancel') }} {{ $t('common.cancel') }}
</div> </a>
</div> </div>
</b-modal> </b-modal>
@ -170,10 +232,26 @@
rounded rounded
size="sm" size="sm"
body-class="list-group-flush p-0 rounded text-center"> body-class="list-group-flush p-0 rounded text-center">
<div class="list-group-item rounded cursor-pointer" @click="shareStatus(status, $event)">{{status.reblogged ? 'Unshare' : 'Share'}} {{ $t('menu.toFollowers') }}</div> <a
<div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">{{ $t('common.copyLink') }}</div> class="list-group-item menu-option"
<div v-if="status && status.local == true && !status.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">{{ $t('menu.embed') }}</div> href="#"
<div class="list-group-item rounded cursor-pointer text-lighter" @click="closeCtxShareMenu()">{{ $t('common.cancel') }}</div> @click.prevent="ctxMenuCopyLink()">
{{ $t('common.copyLink') }}
</a>
<a
v-if="status && status.local == true && !status.in_reply_to_id"
class="list-group-item menu-option"
@click.prevent="ctxMenuEmbed()">
{{ $t('menu.embed') }}
</a>
<a
class="list-group-item menu-option text-lighter"
href="#"
@click.prevent="closeCtxShareMenu()">
{{ $t('common.cancel') }}
</a>
</b-modal> </b-modal>
<b-modal ref="ctxEmbedModal" <b-modal ref="ctxEmbedModal"
@ -339,19 +417,19 @@
ctxMenu() { ctxMenu() {
this.ctxMenuStatus = this.status; this.ctxMenuStatus = this.status;
this.ctxEmbedPayload = window.App.util.embed.post(this.status.url); this.ctxEmbedPayload = window.App.util.embed.post(this.status.url);
// if(this.status.account.id == this.profile.id) { if(this.status.account.id == this.profile.id) {
this.ctxMenuRelationship = false; this.ctxMenuRelationship = false;
this.$refs.ctxModal.show(); this.$refs.ctxModal.show();
// } else { } else {
// axios.get('/api/pixelfed/v1/accounts/relationships', { axios.get('/api/v1/accounts/relationships', {
// params: { params: {
// 'id[]': this.status.account.id 'id[]': this.status.account.id
// } }
// }).then(res => { }).then(res => {
// this.ctxMenuRelationship = res.data[0]; this.ctxMenuRelationship = res.data[0];
// this.$refs.ctxModal.show(); this.$refs.ctxModal.show();
// }); });
// } }
}, },
closeCtxMenu() { closeCtxMenu() {
@ -667,28 +745,6 @@
} }
}, },
shareStatus(status, $event) {
if($('body').hasClass('loggedIn') == false) {
return;
}
this.closeModals();
axios.post('/i/share', {
item: status.id
}).then(res => {
status.reblogs_count = res.data.count;
status.reblogged = !status.reblogged;
// if(status.reblogged) {
// swal('Success', 'You shared this post', 'success');
// } else {
// swal('Success', 'You unshared this post', 'success');
// }
}).catch(err => {
swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
});
},
statusUrl(status) { statusUrl(status) {
if(status.account.local == true) { if(status.account.local == true) {
this.$router.push({ this.$router.push({
@ -741,10 +797,18 @@
return; return;
} }
if(window.confirm(this.$t('menu.deletePostConfirm')) == false) { swal({
return; title: 'Confirm Delete',
} text: 'Are you sure you want to delete this post?',
icon: "warning",
buttons: true,
dangerMode: true,
})
.then(res => {
if(!res) {
this.closeModals();
this.isDeleting = false;
} else {
axios.post('/i/delete', { axios.post('/i/delete', {
type: 'status', type: 'status',
item: status.id item: status.id
@ -753,8 +817,12 @@
this.closeModals(); this.closeModals();
this.isDeleting = false; this.isDeleting = false;
}).catch(err => { }).catch(err => {
this.closeModals();
this.isDeleting = false;
swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error'); swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
}); });
}
})
}, },
owner(status) { owner(status) {
@ -776,7 +844,7 @@
axios.post('/api/pixelfed/v2/status/' + status.id + '/archive') axios.post('/api/pixelfed/v2/status/' + status.id + '/archive')
.then(res => { .then(res => {
this.$emit('status-delete', status.id); this.$emit('delete', status.id);
this.$emit('archived', status.id); this.$emit('archived', status.id);
this.closeModals(); this.closeModals();
}); });
@ -797,7 +865,157 @@
editPost(status) { editPost(status) {
this.closeModals(); this.closeModals();
this.$emit('edit', status); this.$emit('edit', status);
},
handleMute() {
if(!this.ctxMenuRelationship) {
return;
} }
let curState = this.ctxMenuRelationship.muting;
swal({
title: curState ? 'Confirm Unmute' : 'Confirm Mute',
text: curState ? 'Are you sure you want to unmute this account?' : 'Are you sure you want to mute this account?',
icon: "warning",
buttons: true,
dangerMode: true,
})
.then(res => {
if(!res) {
this.closeModals();
} else {
let url = curState ?
`/api/v1/accounts/${this.status.account.id}/unmute` :
`/api/v1/accounts/${this.status.account.id}/mute`;
axios.post(url)
.then(res => {
this.closeModals();
this.$emit('muted', this.status);
this.$store.commit('updateRelationship', [res.data]);
})
.catch(err => {
this.closeModals();
if(err && err.response && err.response.data && err.response.data.error) {
swal('Error', err.response.data.error, 'error');
} else {
swal('Oops!', 'An error occured, please try again later.', 'error');
}
})
}
})
},
handleBlock() {
if(!this.ctxMenuRelationship) {
return;
}
let curState = this.ctxMenuRelationship.blocking;
swal({
title: curState ? 'Confirm Unblock' : 'Confirm Block',
text: curState ? 'Are you sure you want to unblock this account?' : 'Are you sure you want to block this account?',
icon: "warning",
buttons: true,
dangerMode: true,
})
.then(res => {
if(!res) {
this.closeModals();
} else {
let url = curState ?
`/api/v1/accounts/${this.status.account.id}/unblock` :
`/api/v1/accounts/${this.status.account.id}/block`;
axios.post(url)
.then(res => {
this.closeModals();
this.$store.commit('updateRelationship', [res.data]);
this.$emit('muted', this.status);
})
.catch(err => {
this.closeModals();
if(err && err.response && err.response.data && err.response.data.error) {
swal('Error', err.response.data.error, 'error');
} else {
swal('Oops!', 'An error occured, please try again later.', 'error');
}
})
}
})
},
handleUnfollow() {
if(!this.ctxMenuRelationship) {
return;
}
swal({
title: 'Unfollow',
text: 'Are you sure you want to unfollow ' + this.status.account.username + '?',
icon: "warning",
buttons: true,
dangerMode: true,
})
.then(res => {
if(!res) {
this.closeModals();
} else {
axios.post(`/api/v1/accounts/${this.status.account.id}/unfollow`)
.then(res => {
this.closeModals();
this.$store.commit('updateRelationship', [res.data]);
this.$emit('unfollow', this.status);
})
.catch(err => {
this.closeModals();
if(err && err.response && err.response.data && err.response.data.error) {
swal('Error', err.response.data.error, 'error');
} else {
swal('Oops!', 'An error occured, please try again later.', 'error');
}
})
}
})
},
} }
} }
</script> </script>
<style lang="scss" scoped>
.menu-option {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
text-decoration: none;
font-weight: 500;
color: var(--dark);
}
.list-group-item {
border-color: var(--border-color);
}
.action-icon-link {
display: flex;
flex-direction: column;
.icon {
opacity: 0.5;
margin-bottom: 5px;
}
p {
font-weight: 600;
font-size: 11px;
}
&-inline {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 8px;
p {
font-weight: bold;
}
}
}
</style>

View file

@ -91,6 +91,8 @@
v-on:delete="deletePost" v-on:delete="deletePost"
v-on:report-modal="handleReport" v-on:report-modal="handleReport"
v-on:edit="handleEdit" v-on:edit="handleEdit"
v-on:muted="handleMuted"
v-on:unfollow="handleUnfollow"
/> />
<likes-modal <likes-modal
@ -543,6 +545,7 @@
deletePost() { deletePost() {
this.feed.splice(this.postIndex, 1); this.feed.splice(this.postIndex, 1);
this.forceUpdateIdx++;
}, },
counterChange(index, type) { counterChange(index, type) {
@ -788,6 +791,21 @@
.then(res => { .then(res => {
}) })
}, },
handleMuted(post) {
this.feed = this.feed.filter(p => {
return p.account.id !== post.account.id;
});
},
handleUnfollow(post) {
if(this.scope === 'home') {
this.feed = this.feed.filter(p => {
return p.account.id !== post.account.id;
});
}
this.updateProfile({ following_count: this.profile.following_count - 1 });
},
}, },
watch: { watch: {

View file

@ -189,6 +189,10 @@ a.text-dark:hover {
.border { .border {
border: 1px solid var(--border-color) !important; border: 1px solid var(--border-color) !important;
&-right {
border-color: var(--border-color) !important;
}
} }
.bg-white, .bg-white,
@ -396,6 +400,10 @@ span.twitter-typeahead .tt-suggestion:focus {
color: var(--dark); color: var(--dark);
} }
.modal-backdrop {
opacity: 0.8;
}
.timeline-status-component { .timeline-status-component {
.username { .username {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;