|
@@ -2,697 +2,670 @@
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
-use DB;
|
|
|
|
-use Illuminate\Http\Request;
|
|
|
|
-use Illuminate\Support\Str;
|
|
|
|
|
|
+use App\Instance;
|
|
use App\Models\Group;
|
|
use App\Models\Group;
|
|
-use App\Models\GroupActivityGraph;
|
|
|
|
use App\Models\GroupBlock;
|
|
use App\Models\GroupBlock;
|
|
use App\Models\GroupCategory;
|
|
use App\Models\GroupCategory;
|
|
-use App\Models\GroupComment;
|
|
|
|
-use App\Models\GroupEvent;
|
|
|
|
-use App\Models\GroupInteraction;
|
|
|
|
use App\Models\GroupInvitation;
|
|
use App\Models\GroupInvitation;
|
|
-use App\Models\GroupLimit;
|
|
|
|
use App\Models\GroupLike;
|
|
use App\Models\GroupLike;
|
|
|
|
+use App\Models\GroupLimit;
|
|
use App\Models\GroupMember;
|
|
use App\Models\GroupMember;
|
|
use App\Models\GroupPost;
|
|
use App\Models\GroupPost;
|
|
-use App\Models\GroupPostHashtag;
|
|
|
|
use App\Models\GroupReport;
|
|
use App\Models\GroupReport;
|
|
-use App\Models\GroupRole;
|
|
|
|
-use App\Models\GroupStore;
|
|
|
|
-use App\Models\Poll;
|
|
|
|
-use App\Follower;
|
|
|
|
-use App\Instance;
|
|
|
|
-use App\Hashtag;
|
|
|
|
-use App\StatusHashtag;
|
|
|
|
-use App\Like;
|
|
|
|
-use App\Media;
|
|
|
|
-use App\Notification;
|
|
|
|
use App\Profile;
|
|
use App\Profile;
|
|
-use App\Status;
|
|
|
|
-use App\User;
|
|
|
|
-use App\Util\Lexer\Autolink;
|
|
|
|
use App\Services\AccountService;
|
|
use App\Services\AccountService;
|
|
-use App\Services\FollowerService;
|
|
|
|
-use App\Services\HashidService;
|
|
|
|
-use App\Services\LikeService;
|
|
|
|
-use App\Services\Groups\GroupCommentService;
|
|
|
|
-use App\Services\Groups\GroupsLikeService;
|
|
|
|
-use App\Services\HashtagService;
|
|
|
|
use App\Services\GroupService;
|
|
use App\Services\GroupService;
|
|
-use App\Services\GroupFeedService;
|
|
|
|
-use App\Services\GroupPostService;
|
|
|
|
-use App\Services\PollService;
|
|
|
|
-use App\Services\RelationshipService;
|
|
|
|
|
|
+use App\Services\HashidService;
|
|
use App\Services\StatusService;
|
|
use App\Services\StatusService;
|
|
-use App\Services\UserFilterService;
|
|
|
|
-use Cache;
|
|
|
|
|
|
+use App\Status;
|
|
|
|
+use App\User;
|
|
|
|
+use Illuminate\Http\Request;
|
|
use Storage;
|
|
use Storage;
|
|
-use Purify;
|
|
|
|
-use App\Jobs\GroupPipeline\LikePipeline;
|
|
|
|
-use App\Jobs\GroupPipeline\UnlikePipeline;
|
|
|
|
-use App\Jobs\ImageOptimizePipeline\ImageOptimize;
|
|
|
|
-use App\Jobs\VideoPipeline\VideoThumbnail;
|
|
|
|
-use App\Jobs\StatusPipeline\StatusDelete;
|
|
|
|
-use App\Jobs\GroupPipeline\GroupCommentPipeline;
|
|
|
|
-use App\Jobs\GroupPipeline\GroupMemberInvite;
|
|
|
|
-use App\Jobs\GroupPipeline\NewStatusPipeline;
|
|
|
|
-use App\Jobs\GroupPipeline\JoinApproved;
|
|
|
|
-use App\Jobs\GroupPipeline\JoinRejected;
|
|
|
|
-use Illuminate\Support\Facades\RateLimiter;
|
|
|
|
|
|
|
|
class GroupController extends GroupFederationController
|
|
class GroupController extends GroupFederationController
|
|
{
|
|
{
|
|
- public function __construct()
|
|
|
|
- {
|
|
|
|
- // $this->middleware('auth');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function index(Request $request)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- return view('layouts.spa');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function home(Request $request)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- return view('layouts.spa');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function show(Request $request, $id, $path = false)
|
|
|
|
- {
|
|
|
|
- $group = Group::find($id);
|
|
|
|
-
|
|
|
|
- if(!$group || $group->status) {
|
|
|
|
- return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if($request->wantsJson()) {
|
|
|
|
- return $this->showGroupObject($group);
|
|
|
|
- }
|
|
|
|
- return view('layouts.spa', compact('id', 'path'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function showStatus(Request $request, $gid, $sid)
|
|
|
|
- {
|
|
|
|
- $group = Group::find($gid);
|
|
|
|
- $pid = optional($request->user())->profile_id ?? false;
|
|
|
|
-
|
|
|
|
- if(!$group || $group->status) {
|
|
|
|
- return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if($group->is_private) {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $gp = GroupPost::whereGroupId($gid)
|
|
|
|
- ->findOrFail($sid);
|
|
|
|
- return view('layouts.spa', compact('group', 'gp'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function getGroup(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- $group = Group::whereNull('status')->findOrFail($id);
|
|
|
|
- $pid = optional($request->user())->profile_id ?? false;
|
|
|
|
-
|
|
|
|
- $group = $this->toJson($group, $pid);
|
|
|
|
-
|
|
|
|
- return response()->json($group, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public function showStatusLikes(Request $request, $id, $sid)
|
|
|
|
- {
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $user = $request->user();
|
|
|
|
- $pid = $user->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- $status = GroupPost::whereGroupId($id)->findOrFail($sid);
|
|
|
|
- $likes = GroupLike::whereStatusId($sid)
|
|
|
|
- ->cursorPaginate(10)
|
|
|
|
- ->map(function($l) use($group) {
|
|
|
|
- $account = AccountService::get($l->profile_id);
|
|
|
|
- $account['url'] = "/groups/{$group->id}/user/{$account['id']}";
|
|
|
|
- return $account;
|
|
|
|
- })
|
|
|
|
- ->filter(function($l) {
|
|
|
|
- return $l && isset($l['id']);
|
|
|
|
- })
|
|
|
|
- ->values();
|
|
|
|
- return $likes;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupSettings(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- abort_if(!in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
-
|
|
|
|
- return view('groups.settings', compact('group'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function joinGroup(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if($group->isMember($pid), 404);
|
|
|
|
-
|
|
|
|
- if(!$request->user()->is_admin) {
|
|
|
|
- abort_if(GroupService::getRejoinTimeout($group->id, $pid), 422, 'Cannot re-join this group for 24 hours after leaving or cancelling a request to join');
|
|
|
|
|
|
+ public function __construct()
|
|
|
|
+ {
|
|
|
|
+ $this->middleware('auth');
|
|
|
|
+ abort_unless(config('groups.enabled'), 404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function index(Request $request)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+
|
|
|
|
+ return view('layouts.spa');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function home(Request $request)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+
|
|
|
|
+ return view('layouts.spa');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function show(Request $request, $id, $path = false)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::find($id);
|
|
|
|
+
|
|
|
|
+ if (! $group || $group->status) {
|
|
|
|
+ return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ($request->wantsJson()) {
|
|
|
|
+ return $this->showGroupObject($group);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return view('layouts.spa', compact('id', 'path'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function showStatus(Request $request, $gid, $sid)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::find($gid);
|
|
|
|
+ $pid = optional($request->user())->profile_id ?? false;
|
|
|
|
+
|
|
|
|
+ if (! $group || $group->status) {
|
|
|
|
+ return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ($group->is_private) {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $gp = GroupPost::whereGroupId($gid)
|
|
|
|
+ ->findOrFail($sid);
|
|
|
|
+
|
|
|
|
+ return view('layouts.spa', compact('group', 'gp'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function getGroup(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::whereNull('status')->findOrFail($id);
|
|
|
|
+ $pid = optional($request->user())->profile_id ?? false;
|
|
|
|
+
|
|
|
|
+ $group = $this->toJson($group, $pid);
|
|
|
|
+
|
|
|
|
+ return response()->json($group, 200, [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function showStatusLikes(Request $request, $id, $sid)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $user = $request->user();
|
|
|
|
+ $pid = $user->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ $status = GroupPost::whereGroupId($id)->findOrFail($sid);
|
|
|
|
+ $likes = GroupLike::whereStatusId($sid)
|
|
|
|
+ ->cursorPaginate(10)
|
|
|
|
+ ->map(function ($l) use ($group) {
|
|
|
|
+ $account = AccountService::get($l->profile_id);
|
|
|
|
+ $account['url'] = "/groups/{$group->id}/user/{$account['id']}";
|
|
|
|
+
|
|
|
|
+ return $account;
|
|
|
|
+ })
|
|
|
|
+ ->filter(function ($l) {
|
|
|
|
+ return $l && isset($l['id']);
|
|
|
|
+ })
|
|
|
|
+ ->values();
|
|
|
|
+
|
|
|
|
+ return $likes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupSettings(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ abort_if(! in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
+
|
|
|
|
+ return view('groups.settings', compact('group'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function joinGroup(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if($group->isMember($pid), 404);
|
|
|
|
+
|
|
|
|
+ if (! $request->user()->is_admin) {
|
|
|
|
+ abort_if(GroupService::getRejoinTimeout($group->id, $pid), 422, 'Cannot re-join this group for 24 hours after leaving or cancelling a request to join');
|
|
}
|
|
}
|
|
|
|
|
|
- $member = new GroupMember;
|
|
|
|
- $member->group_id = $group->id;
|
|
|
|
- $member->profile_id = $pid;
|
|
|
|
- $member->role = 'member';
|
|
|
|
- $member->local_group = true;
|
|
|
|
- $member->local_profile = true;
|
|
|
|
- $member->join_request = $group->is_private;
|
|
|
|
- $member->save();
|
|
|
|
-
|
|
|
|
- GroupService::delSelf($group->id, $pid);
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:joined',
|
|
|
|
- null,
|
|
|
|
- GroupMember::class,
|
|
|
|
- $member->id
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- $group = $this->toJson($group, $pid);
|
|
|
|
-
|
|
|
|
- return $group;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function updateGroup(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- $this->validate($request, [
|
|
|
|
- 'description' => 'nullable|max:500',
|
|
|
|
- 'membership' => 'required|in:all,local,private',
|
|
|
|
- 'avatar' => 'nullable',
|
|
|
|
- 'header' => 'nullable',
|
|
|
|
- 'discoverable' => 'required',
|
|
|
|
- 'activitypub' => 'required',
|
|
|
|
- 'is_nsfw' => 'required',
|
|
|
|
- 'category' => 'required|string|in:' . implode(',',GroupService::categories())
|
|
|
|
- ]);
|
|
|
|
-
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::whereProfileId($pid)->findOrFail($id);
|
|
|
|
- $member = GroupMember::whereGroupId($group->id)->whereProfileId($pid)->firstOrFail();
|
|
|
|
-
|
|
|
|
- abort_if($member->role != 'founder', 403, 'Invalid group permission');
|
|
|
|
-
|
|
|
|
- $metadata = $group->metadata;
|
|
|
|
- $len = $group->is_private ? 12 : 4;
|
|
|
|
-
|
|
|
|
- if($request->hasFile('avatar')) {
|
|
|
|
- $avatar = $request->file('avatar');
|
|
|
|
-
|
|
|
|
- if($avatar) {
|
|
|
|
- if( isset($metadata['avatar']) &&
|
|
|
|
- isset($metadata['avatar']['path']) &&
|
|
|
|
- Storage::exists($metadata['avatar']['path'])
|
|
|
|
- ) {
|
|
|
|
- Storage::delete($metadata['avatar']['path']);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $fileName = 'avatar_' . strtolower(str_random($len)) . '.' . $avatar->extension();
|
|
|
|
- $path = $avatar->storePubliclyAs('public/g/'.$group->id.'/meta', $fileName);
|
|
|
|
- $url = url(Storage::url($path));
|
|
|
|
- $metadata['avatar'] = [
|
|
|
|
- 'path' => $path,
|
|
|
|
- 'url' => $url,
|
|
|
|
- 'updated_at' => now()
|
|
|
|
- ];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if($request->hasFile('header')) {
|
|
|
|
- $header = $request->file('header');
|
|
|
|
-
|
|
|
|
- if($header) {
|
|
|
|
- if( isset($metadata['header']) &&
|
|
|
|
- isset($metadata['header']['path']) &&
|
|
|
|
- Storage::exists($metadata['header']['path'])
|
|
|
|
- ) {
|
|
|
|
- Storage::delete($metadata['header']['path']);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $fileName = 'header_' . strtolower(str_random($len)) . '.' . $header->extension();
|
|
|
|
- $path = $header->storePubliclyAs('public/g/'.$group->id.'/meta', $fileName);
|
|
|
|
- $url = url(Storage::url($path));
|
|
|
|
- $metadata['header'] = [
|
|
|
|
- 'path' => $path,
|
|
|
|
- 'url' => $url,
|
|
|
|
- 'updated_at' => now()
|
|
|
|
- ];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $cat = GroupService::categoryById($group->category_id);
|
|
|
|
- if($request->category !== $cat['name']) {
|
|
|
|
- $group->category_id = GroupCategory::whereName($request->category)->first()->id;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $changes = null;
|
|
|
|
- $group->description = e($request->input('description', null));
|
|
|
|
- $group->is_private = $request->input('membership') == 'private';
|
|
|
|
- $group->local_only = $request->input('membership') == 'local';
|
|
|
|
- $group->activitypub = $request->input('activitypub') == "true";
|
|
|
|
- $group->discoverable = $request->input('discoverable') == "true";
|
|
|
|
- $group->is_nsfw = $request->input('is_nsfw') == "true";
|
|
|
|
- $group->metadata = $metadata;
|
|
|
|
- if($group->isDirty()) {
|
|
|
|
- $changes = $group->getDirty();
|
|
|
|
- }
|
|
|
|
- $group->save();
|
|
|
|
-
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:settings:updated',
|
|
|
|
- $changes
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- GroupService::del($group->id);
|
|
|
|
-
|
|
|
|
- $res = $this->toJson($group, $pid);
|
|
|
|
- return $res;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected function toJson($group, $pid = false)
|
|
|
|
- {
|
|
|
|
- return GroupService::get($group->id, $pid);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupLeave(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
-
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
-
|
|
|
|
- abort_if($pid == $group->profile_id, 422, 'Cannot leave a group you created');
|
|
|
|
-
|
|
|
|
- abort_if(!$group->isMember($pid), 403, 'Not a member of group.');
|
|
|
|
-
|
|
|
|
- GroupMember::whereGroupId($group->id)->whereProfileId($pid)->delete();
|
|
|
|
- GroupService::del($group->id);
|
|
|
|
- GroupService::delSelf($group->id, $pid);
|
|
|
|
- GroupService::setRejoinTimeout($group->id, $pid);
|
|
|
|
-
|
|
|
|
- return [200];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function cancelJoinRequest(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
-
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
-
|
|
|
|
- abort_if($pid == $group->profile_id, 422, 'Cannot leave a group you created');
|
|
|
|
- abort_if($group->isMember($pid), 422, 'Cannot cancel approved join request, please leave group instead.');
|
|
|
|
-
|
|
|
|
- GroupMember::whereGroupId($group->id)->whereProfileId($pid)->delete();
|
|
|
|
- GroupService::del($group->id);
|
|
|
|
- GroupService::delSelf($group->id, $pid);
|
|
|
|
- GroupService::setRejoinTimeout($group->id, $pid);
|
|
|
|
-
|
|
|
|
- return [200];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function metaBlockSearch(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- abort_if(!in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
-
|
|
|
|
- $type = $request->input('type');
|
|
|
|
- $item = $request->input('item');
|
|
|
|
-
|
|
|
|
- switch($type) {
|
|
|
|
- case 'instance':
|
|
|
|
- $res = Instance::whereDomain($item)->first();
|
|
|
|
- if($res) {
|
|
|
|
- abort_if(GroupBlock::whereGroupId($group->id)->whereInstanceId($res->id)->exists(), 400);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'user':
|
|
|
|
- $res = Profile::whereUsername($item)->first();
|
|
|
|
- if($res) {
|
|
|
|
- abort_if(GroupBlock::whereGroupId($group->id)->whereProfileId($res->id)->exists(), 400);
|
|
|
|
- }
|
|
|
|
- if($res->user_id != null) {
|
|
|
|
- abort_if(User::whereIsAdmin(true)->whereId($res->user_id)->exists(), 400);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return response()->json((bool) $res, ($res ? 200 : 404));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function reportCreate(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
-
|
|
|
|
- $id = $request->input('id');
|
|
|
|
- $type = $request->input('type');
|
|
|
|
- $types = [
|
|
|
|
- // original 3
|
|
|
|
- 'spam',
|
|
|
|
- 'sensitive',
|
|
|
|
- 'abusive',
|
|
|
|
-
|
|
|
|
- // new
|
|
|
|
- 'underage',
|
|
|
|
|
|
+ $member = new GroupMember;
|
|
|
|
+ $member->group_id = $group->id;
|
|
|
|
+ $member->profile_id = $pid;
|
|
|
|
+ $member->role = 'member';
|
|
|
|
+ $member->local_group = true;
|
|
|
|
+ $member->local_profile = true;
|
|
|
|
+ $member->join_request = $group->is_private;
|
|
|
|
+ $member->save();
|
|
|
|
+
|
|
|
|
+ GroupService::delSelf($group->id, $pid);
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:joined',
|
|
|
|
+ null,
|
|
|
|
+ GroupMember::class,
|
|
|
|
+ $member->id
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ $group = $this->toJson($group, $pid);
|
|
|
|
+
|
|
|
|
+ return $group;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function updateGroup(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ $this->validate($request, [
|
|
|
|
+ 'description' => 'nullable|max:500',
|
|
|
|
+ 'membership' => 'required|in:all,local,private',
|
|
|
|
+ 'avatar' => 'nullable',
|
|
|
|
+ 'header' => 'nullable',
|
|
|
|
+ 'discoverable' => 'required',
|
|
|
|
+ 'activitypub' => 'required',
|
|
|
|
+ 'is_nsfw' => 'required',
|
|
|
|
+ 'category' => 'required|string|in:'.implode(',', GroupService::categories()),
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::whereProfileId($pid)->findOrFail($id);
|
|
|
|
+ $member = GroupMember::whereGroupId($group->id)->whereProfileId($pid)->firstOrFail();
|
|
|
|
+
|
|
|
|
+ abort_if($member->role != 'founder', 403, 'Invalid group permission');
|
|
|
|
+
|
|
|
|
+ $metadata = $group->metadata;
|
|
|
|
+ $len = $group->is_private ? 12 : 4;
|
|
|
|
+
|
|
|
|
+ if ($request->hasFile('avatar')) {
|
|
|
|
+ $avatar = $request->file('avatar');
|
|
|
|
+
|
|
|
|
+ if ($avatar) {
|
|
|
|
+ if (isset($metadata['avatar']) &&
|
|
|
|
+ isset($metadata['avatar']['path']) &&
|
|
|
|
+ Storage::exists($metadata['avatar']['path'])
|
|
|
|
+ ) {
|
|
|
|
+ Storage::delete($metadata['avatar']['path']);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $fileName = 'avatar_'.strtolower(str_random($len)).'.'.$avatar->extension();
|
|
|
|
+ $path = $avatar->storePubliclyAs('public/g/'.$group->id.'/meta', $fileName);
|
|
|
|
+ $url = url(Storage::url($path));
|
|
|
|
+ $metadata['avatar'] = [
|
|
|
|
+ 'path' => $path,
|
|
|
|
+ 'url' => $url,
|
|
|
|
+ 'updated_at' => now(),
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ($request->hasFile('header')) {
|
|
|
|
+ $header = $request->file('header');
|
|
|
|
+
|
|
|
|
+ if ($header) {
|
|
|
|
+ if (isset($metadata['header']) &&
|
|
|
|
+ isset($metadata['header']['path']) &&
|
|
|
|
+ Storage::exists($metadata['header']['path'])
|
|
|
|
+ ) {
|
|
|
|
+ Storage::delete($metadata['header']['path']);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $fileName = 'header_'.strtolower(str_random($len)).'.'.$header->extension();
|
|
|
|
+ $path = $header->storePubliclyAs('public/g/'.$group->id.'/meta', $fileName);
|
|
|
|
+ $url = url(Storage::url($path));
|
|
|
|
+ $metadata['header'] = [
|
|
|
|
+ 'path' => $path,
|
|
|
|
+ 'url' => $url,
|
|
|
|
+ 'updated_at' => now(),
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $cat = GroupService::categoryById($group->category_id);
|
|
|
|
+ if ($request->category !== $cat['name']) {
|
|
|
|
+ $group->category_id = GroupCategory::whereName($request->category)->first()->id;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $changes = null;
|
|
|
|
+ $group->description = e($request->input('description', null));
|
|
|
|
+ $group->is_private = $request->input('membership') == 'private';
|
|
|
|
+ $group->local_only = $request->input('membership') == 'local';
|
|
|
|
+ $group->activitypub = $request->input('activitypub') == 'true';
|
|
|
|
+ $group->discoverable = $request->input('discoverable') == 'true';
|
|
|
|
+ $group->is_nsfw = $request->input('is_nsfw') == 'true';
|
|
|
|
+ $group->metadata = $metadata;
|
|
|
|
+ if ($group->isDirty()) {
|
|
|
|
+ $changes = $group->getDirty();
|
|
|
|
+ }
|
|
|
|
+ $group->save();
|
|
|
|
+
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:settings:updated',
|
|
|
|
+ $changes
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ GroupService::del($group->id);
|
|
|
|
+
|
|
|
|
+ $res = $this->toJson($group, $pid);
|
|
|
|
+
|
|
|
|
+ return $res;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected function toJson($group, $pid = false)
|
|
|
|
+ {
|
|
|
|
+ return GroupService::get($group->id, $pid);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupLeave(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+
|
|
|
|
+ abort_if($pid == $group->profile_id, 422, 'Cannot leave a group you created');
|
|
|
|
+
|
|
|
|
+ abort_if(! $group->isMember($pid), 403, 'Not a member of group.');
|
|
|
|
+
|
|
|
|
+ GroupMember::whereGroupId($group->id)->whereProfileId($pid)->delete();
|
|
|
|
+ GroupService::del($group->id);
|
|
|
|
+ GroupService::delSelf($group->id, $pid);
|
|
|
|
+ GroupService::setRejoinTimeout($group->id, $pid);
|
|
|
|
+
|
|
|
|
+ return [200];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function cancelJoinRequest(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+
|
|
|
|
+ abort_if($pid == $group->profile_id, 422, 'Cannot leave a group you created');
|
|
|
|
+ abort_if($group->isMember($pid), 422, 'Cannot cancel approved join request, please leave group instead.');
|
|
|
|
+
|
|
|
|
+ GroupMember::whereGroupId($group->id)->whereProfileId($pid)->delete();
|
|
|
|
+ GroupService::del($group->id);
|
|
|
|
+ GroupService::delSelf($group->id, $pid);
|
|
|
|
+ GroupService::setRejoinTimeout($group->id, $pid);
|
|
|
|
+
|
|
|
|
+ return [200];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function metaBlockSearch(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ abort_if(! in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
+
|
|
|
|
+ $type = $request->input('type');
|
|
|
|
+ $item = $request->input('item');
|
|
|
|
+
|
|
|
|
+ switch ($type) {
|
|
|
|
+ case 'instance':
|
|
|
|
+ $res = Instance::whereDomain($item)->first();
|
|
|
|
+ if ($res) {
|
|
|
|
+ abort_if(GroupBlock::whereGroupId($group->id)->whereInstanceId($res->id)->exists(), 400);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'user':
|
|
|
|
+ $res = Profile::whereUsername($item)->first();
|
|
|
|
+ if ($res) {
|
|
|
|
+ abort_if(GroupBlock::whereGroupId($group->id)->whereProfileId($res->id)->exists(), 400);
|
|
|
|
+ }
|
|
|
|
+ if ($res->user_id != null) {
|
|
|
|
+ abort_if(User::whereIsAdmin(true)->whereId($res->user_id)->exists(), 400);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return response()->json((bool) $res, ($res ? 200 : 404));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function reportCreate(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+
|
|
|
|
+ $id = $request->input('id');
|
|
|
|
+ $type = $request->input('type');
|
|
|
|
+ $types = [
|
|
|
|
+ // original 3
|
|
|
|
+ 'spam',
|
|
|
|
+ 'sensitive',
|
|
|
|
+ 'abusive',
|
|
|
|
+
|
|
|
|
+ // new
|
|
|
|
+ 'underage',
|
|
'violence',
|
|
'violence',
|
|
- 'copyright',
|
|
|
|
- 'impersonation',
|
|
|
|
- 'scam',
|
|
|
|
- 'terrorism'
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
- $gp = GroupPost::whereGroupId($group->id)->find($id);
|
|
|
|
- abort_if(!$gp, 422, 'Cannot report an invalid or deleted post');
|
|
|
|
- abort_if(!in_array($type, $types), 422, 'Invalid report type');
|
|
|
|
- abort_if($gp->profile_id === $pid, 422, 'Cannot report your own post');
|
|
|
|
- abort_if(
|
|
|
|
- GroupReport::whereGroupId($group->id)
|
|
|
|
- ->whereProfileId($pid)
|
|
|
|
- ->whereItemType(GroupPost::class)
|
|
|
|
- ->whereItemId($id)
|
|
|
|
- ->exists(),
|
|
|
|
- 422,
|
|
|
|
- 'You already reported this'
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- $report = new GroupReport();
|
|
|
|
- $report->group_id = $group->id;
|
|
|
|
- $report->profile_id = $pid;
|
|
|
|
- $report->type = $type;
|
|
|
|
- $report->item_type = GroupPost::class;
|
|
|
|
- $report->item_id = $id;
|
|
|
|
- $report->open = true;
|
|
|
|
- $report->save();
|
|
|
|
-
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:report:create',
|
|
|
|
- [
|
|
|
|
- 'type' => $type,
|
|
|
|
- 'report_id' => $report->id,
|
|
|
|
- 'status_id' => $gp->status_id,
|
|
|
|
- 'profile_id' => $gp->profile_id,
|
|
|
|
- 'username' => optional(AccountService::get($gp->profile_id))['acct'],
|
|
|
|
- 'gpid' => $gp->id,
|
|
|
|
- 'url' => $gp->url()
|
|
|
|
- ],
|
|
|
|
- GroupReport::class,
|
|
|
|
- $report->id
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- return response([200]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function reportAction(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- abort_if(!in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
-
|
|
|
|
- $this->validate($request, [
|
|
|
|
- 'action' => 'required|in:cw,delete,ignore',
|
|
|
|
- 'id' => 'required|string'
|
|
|
|
- ]);
|
|
|
|
-
|
|
|
|
- $action = $request->input('action');
|
|
|
|
- $id = $request->input('id');
|
|
|
|
-
|
|
|
|
- $report = GroupReport::whereGroupId($group->id)
|
|
|
|
- ->findOrFail($id);
|
|
|
|
- $status = Status::findOrFail($report->item_id);
|
|
|
|
- $gp = GroupPost::whereGroupId($group->id)
|
|
|
|
- ->whereStatusId($status->id)
|
|
|
|
- ->firstOrFail();
|
|
|
|
-
|
|
|
|
- switch ($action) {
|
|
|
|
- case 'cw':
|
|
|
|
- $status->is_nsfw = true;
|
|
|
|
- $status->save();
|
|
|
|
- StatusService::del($status->id);
|
|
|
|
-
|
|
|
|
- GroupReport::whereGroupId($group->id)
|
|
|
|
- ->whereItemType($report->item_type)
|
|
|
|
- ->whereItemId($report->item_id)
|
|
|
|
- ->update(['open' => false]);
|
|
|
|
-
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:moderation:action',
|
|
|
|
- [
|
|
|
|
- 'type' => 'cw',
|
|
|
|
- 'report_id' => $report->id,
|
|
|
|
- 'status_id' => $status->id,
|
|
|
|
- 'profile_id' => $status->profile_id,
|
|
|
|
- 'status_url' => $gp->url()
|
|
|
|
- ],
|
|
|
|
- GroupReport::class,
|
|
|
|
- $report->id
|
|
|
|
- );
|
|
|
|
- return response()->json([200]);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'ignore':
|
|
|
|
- GroupReport::whereGroupId($group->id)
|
|
|
|
- ->whereItemType($report->item_type)
|
|
|
|
- ->whereItemId($report->item_id)
|
|
|
|
- ->update(['open' => false]);
|
|
|
|
-
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:moderation:action',
|
|
|
|
- [
|
|
|
|
- 'type' => 'ignore',
|
|
|
|
- 'report_id' => $report->id,
|
|
|
|
- 'status_id' => $status->id,
|
|
|
|
- 'profile_id' => $status->profile_id,
|
|
|
|
- 'status_url' => $gp->url()
|
|
|
|
- ],
|
|
|
|
- GroupReport::class,
|
|
|
|
- $report->id
|
|
|
|
- );
|
|
|
|
- return response()->json([200]);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function getMemberInteractionLimits(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- abort_if(!in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
-
|
|
|
|
- $profile_id = $request->input('profile_id');
|
|
|
|
- abort_if(!$group->isMember($profile_id), 404);
|
|
|
|
- $limits = GroupService::getInteractionLimits($group->id, $profile_id);
|
|
|
|
- return response()->json($limits);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function updateMemberInteractionLimits(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- abort_if(!$group->isMember($pid), 404);
|
|
|
|
- abort_if(!in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
-
|
|
|
|
- $this->validate($request, [
|
|
|
|
- 'profile_id' => 'required|exists:profiles,id',
|
|
|
|
- 'can_post' => 'required',
|
|
|
|
- 'can_comment' => 'required',
|
|
|
|
- 'can_like' => 'required'
|
|
|
|
- ]);
|
|
|
|
-
|
|
|
|
- $member = $request->input('profile_id');
|
|
|
|
- $can_post = $request->input('can_post');
|
|
|
|
- $can_comment = $request->input('can_comment');
|
|
|
|
- $can_like = $request->input('can_like');
|
|
|
|
- $account = AccountService::get($member);
|
|
|
|
-
|
|
|
|
- abort_if(!$account, 422, 'Invalid profile');
|
|
|
|
- abort_if(!$group->isMember($member), 422, 'Invalid profile');
|
|
|
|
-
|
|
|
|
- $limit = GroupLimit::firstOrCreate([
|
|
|
|
- 'profile_id' => $member,
|
|
|
|
- 'group_id' => $group->id
|
|
|
|
- ]);
|
|
|
|
-
|
|
|
|
- if($limit->wasRecentlyCreated) {
|
|
|
|
- abort_if(GroupLimit::whereGroupId($group->id)->count() >= 25, 422, 'limit_reached');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $previousLimits = $limit->limits;
|
|
|
|
-
|
|
|
|
- $limit->limits = [
|
|
|
|
- 'can_post' => $can_post,
|
|
|
|
- 'can_comment' => $can_comment,
|
|
|
|
- 'can_like' => $can_like
|
|
|
|
- ];
|
|
|
|
- $limit->save();
|
|
|
|
-
|
|
|
|
- GroupService::clearInteractionLimits($group->id, $member);
|
|
|
|
-
|
|
|
|
- GroupService::log(
|
|
|
|
- $group->id,
|
|
|
|
- $pid,
|
|
|
|
- 'group:member-limits:updated',
|
|
|
|
- [
|
|
|
|
- 'profile_id' => $account['id'],
|
|
|
|
- 'username' => $account['username'],
|
|
|
|
- 'previousLimits' => $previousLimits,
|
|
|
|
- 'newLimits' => $limit->limits
|
|
|
|
- ],
|
|
|
|
- GroupLimit::class,
|
|
|
|
- $limit->id
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- return $request->all();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public function showProfile(Request $request, $id, $pid)
|
|
|
|
- {
|
|
|
|
- $group = Group::find($id);
|
|
|
|
-
|
|
|
|
- if(!$group || $group->status) {
|
|
|
|
- return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return view('layouts.spa');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function showProfileByUsername(Request $request, $id, $pid)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- if(!$request->user()) {
|
|
|
|
- return redirect("/{$pid}");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $group = Group::find($id);
|
|
|
|
- $cid = $request->user()->profile_id;
|
|
|
|
-
|
|
|
|
- if(!$group || $group->status) {
|
|
|
|
- return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(!$group->isMember($cid)) {
|
|
|
|
- return redirect("/{$pid}");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $profile = Profile::whereUsername($pid)->first();
|
|
|
|
-
|
|
|
|
- if(!$group->isMember($profile->id)) {
|
|
|
|
- return redirect("/{$pid}");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if($profile) {
|
|
|
|
- $url = url("/groups/{$id}/user/{$profile->id}");
|
|
|
|
- return redirect($url);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- abort(404, 'Invalid username');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- public function groupInviteLanding(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort(404, 'Not yet implemented');
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- return view('groups.invite', compact('group'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupShortLinkRedirect(Request $request, $hid)
|
|
|
|
- {
|
|
|
|
- $gid = HashidService::decode($hid);
|
|
|
|
- $group = Group::findOrFail($gid);
|
|
|
|
- return redirect($group->url());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupInviteClaim(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- $group = GroupService::get($id);
|
|
|
|
- abort_if(!$group || empty($group), 404);
|
|
|
|
- return view('groups.invite-claim', compact('group'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupMemberInviteCheck(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
-
|
|
|
|
- $exists = GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->exists();
|
|
|
|
-
|
|
|
|
- return response()->json([
|
|
|
|
- 'gid' => $id,
|
|
|
|
- 'can_join' => (bool) $exists
|
|
|
|
- ]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupMemberInviteAccept(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
-
|
|
|
|
- abort_if(!GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->exists(), 422);
|
|
|
|
-
|
|
|
|
- $gm = new GroupMember;
|
|
|
|
- $gm->group_id = $id;
|
|
|
|
- $gm->profile_id = $pid;
|
|
|
|
- $gm->role = 'member';
|
|
|
|
- $gm->local_group = $group->local;
|
|
|
|
- $gm->local_profile = true;
|
|
|
|
- $gm->join_request = false;
|
|
|
|
- $gm->save();
|
|
|
|
-
|
|
|
|
- GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->delete();
|
|
|
|
- GroupService::del($id);
|
|
|
|
- GroupService::delSelf($id, $pid);
|
|
|
|
-
|
|
|
|
- return ['next_url' => $group->url()];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function groupMemberInviteDecline(Request $request, $id)
|
|
|
|
- {
|
|
|
|
- abort_if(!$request->user(), 404);
|
|
|
|
- $pid = $request->user()->profile_id;
|
|
|
|
- $group = Group::findOrFail($id);
|
|
|
|
- abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
- return ['next_url' => '/'];
|
|
|
|
- }
|
|
|
|
|
|
+ 'copyright',
|
|
|
|
+ 'impersonation',
|
|
|
|
+ 'scam',
|
|
|
|
+ 'terrorism',
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ $gp = GroupPost::whereGroupId($group->id)->find($id);
|
|
|
|
+ abort_if(! $gp, 422, 'Cannot report an invalid or deleted post');
|
|
|
|
+ abort_if(! in_array($type, $types), 422, 'Invalid report type');
|
|
|
|
+ abort_if($gp->profile_id === $pid, 422, 'Cannot report your own post');
|
|
|
|
+ abort_if(
|
|
|
|
+ GroupReport::whereGroupId($group->id)
|
|
|
|
+ ->whereProfileId($pid)
|
|
|
|
+ ->whereItemType(GroupPost::class)
|
|
|
|
+ ->whereItemId($id)
|
|
|
|
+ ->exists(),
|
|
|
|
+ 422,
|
|
|
|
+ 'You already reported this'
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ $report = new GroupReport();
|
|
|
|
+ $report->group_id = $group->id;
|
|
|
|
+ $report->profile_id = $pid;
|
|
|
|
+ $report->type = $type;
|
|
|
|
+ $report->item_type = GroupPost::class;
|
|
|
|
+ $report->item_id = $id;
|
|
|
|
+ $report->open = true;
|
|
|
|
+ $report->save();
|
|
|
|
+
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:report:create',
|
|
|
|
+ [
|
|
|
|
+ 'type' => $type,
|
|
|
|
+ 'report_id' => $report->id,
|
|
|
|
+ 'status_id' => $gp->status_id,
|
|
|
|
+ 'profile_id' => $gp->profile_id,
|
|
|
|
+ 'username' => optional(AccountService::get($gp->profile_id))['acct'],
|
|
|
|
+ 'gpid' => $gp->id,
|
|
|
|
+ 'url' => $gp->url(),
|
|
|
|
+ ],
|
|
|
|
+ GroupReport::class,
|
|
|
|
+ $report->id
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return response([200]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function reportAction(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ abort_if(! in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
+
|
|
|
|
+ $this->validate($request, [
|
|
|
|
+ 'action' => 'required|in:cw,delete,ignore',
|
|
|
|
+ 'id' => 'required|string',
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ $action = $request->input('action');
|
|
|
|
+ $id = $request->input('id');
|
|
|
|
+
|
|
|
|
+ $report = GroupReport::whereGroupId($group->id)
|
|
|
|
+ ->findOrFail($id);
|
|
|
|
+ $status = Status::findOrFail($report->item_id);
|
|
|
|
+ $gp = GroupPost::whereGroupId($group->id)
|
|
|
|
+ ->whereStatusId($status->id)
|
|
|
|
+ ->firstOrFail();
|
|
|
|
+
|
|
|
|
+ switch ($action) {
|
|
|
|
+ case 'cw':
|
|
|
|
+ $status->is_nsfw = true;
|
|
|
|
+ $status->save();
|
|
|
|
+ StatusService::del($status->id);
|
|
|
|
+
|
|
|
|
+ GroupReport::whereGroupId($group->id)
|
|
|
|
+ ->whereItemType($report->item_type)
|
|
|
|
+ ->whereItemId($report->item_id)
|
|
|
|
+ ->update(['open' => false]);
|
|
|
|
+
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:moderation:action',
|
|
|
|
+ [
|
|
|
|
+ 'type' => 'cw',
|
|
|
|
+ 'report_id' => $report->id,
|
|
|
|
+ 'status_id' => $status->id,
|
|
|
|
+ 'profile_id' => $status->profile_id,
|
|
|
|
+ 'status_url' => $gp->url(),
|
|
|
|
+ ],
|
|
|
|
+ GroupReport::class,
|
|
|
|
+ $report->id
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return response()->json([200]);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'ignore':
|
|
|
|
+ GroupReport::whereGroupId($group->id)
|
|
|
|
+ ->whereItemType($report->item_type)
|
|
|
|
+ ->whereItemId($report->item_id)
|
|
|
|
+ ->update(['open' => false]);
|
|
|
|
+
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:moderation:action',
|
|
|
|
+ [
|
|
|
|
+ 'type' => 'ignore',
|
|
|
|
+ 'report_id' => $report->id,
|
|
|
|
+ 'status_id' => $status->id,
|
|
|
|
+ 'profile_id' => $status->profile_id,
|
|
|
|
+ 'status_url' => $gp->url(),
|
|
|
|
+ ],
|
|
|
|
+ GroupReport::class,
|
|
|
|
+ $report->id
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return response()->json([200]);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function getMemberInteractionLimits(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ abort_if(! in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
+
|
|
|
|
+ $profile_id = $request->input('profile_id');
|
|
|
|
+ abort_if(! $group->isMember($profile_id), 404);
|
|
|
|
+ $limits = GroupService::getInteractionLimits($group->id, $profile_id);
|
|
|
|
+
|
|
|
|
+ return response()->json($limits);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function updateMemberInteractionLimits(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ abort_if(! $group->isMember($pid), 404);
|
|
|
|
+ abort_if(! in_array($group->selfRole($pid), ['founder', 'admin']), 404);
|
|
|
|
+
|
|
|
|
+ $this->validate($request, [
|
|
|
|
+ 'profile_id' => 'required|exists:profiles,id',
|
|
|
|
+ 'can_post' => 'required',
|
|
|
|
+ 'can_comment' => 'required',
|
|
|
|
+ 'can_like' => 'required',
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ $member = $request->input('profile_id');
|
|
|
|
+ $can_post = $request->input('can_post');
|
|
|
|
+ $can_comment = $request->input('can_comment');
|
|
|
|
+ $can_like = $request->input('can_like');
|
|
|
|
+ $account = AccountService::get($member);
|
|
|
|
+
|
|
|
|
+ abort_if(! $account, 422, 'Invalid profile');
|
|
|
|
+ abort_if(! $group->isMember($member), 422, 'Invalid profile');
|
|
|
|
+
|
|
|
|
+ $limit = GroupLimit::firstOrCreate([
|
|
|
|
+ 'profile_id' => $member,
|
|
|
|
+ 'group_id' => $group->id,
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ if ($limit->wasRecentlyCreated) {
|
|
|
|
+ abort_if(GroupLimit::whereGroupId($group->id)->count() >= 25, 422, 'limit_reached');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $previousLimits = $limit->limits;
|
|
|
|
+
|
|
|
|
+ $limit->limits = [
|
|
|
|
+ 'can_post' => $can_post,
|
|
|
|
+ 'can_comment' => $can_comment,
|
|
|
|
+ 'can_like' => $can_like,
|
|
|
|
+ ];
|
|
|
|
+ $limit->save();
|
|
|
|
+
|
|
|
|
+ GroupService::clearInteractionLimits($group->id, $member);
|
|
|
|
+
|
|
|
|
+ GroupService::log(
|
|
|
|
+ $group->id,
|
|
|
|
+ $pid,
|
|
|
|
+ 'group:member-limits:updated',
|
|
|
|
+ [
|
|
|
|
+ 'profile_id' => $account['id'],
|
|
|
|
+ 'username' => $account['username'],
|
|
|
|
+ 'previousLimits' => $previousLimits,
|
|
|
|
+ 'newLimits' => $limit->limits,
|
|
|
|
+ ],
|
|
|
|
+ GroupLimit::class,
|
|
|
|
+ $limit->id
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return $request->all();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function showProfile(Request $request, $id, $pid)
|
|
|
|
+ {
|
|
|
|
+ $group = Group::find($id);
|
|
|
|
+
|
|
|
|
+ if (! $group || $group->status) {
|
|
|
|
+ return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return view('layouts.spa');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function showProfileByUsername(Request $request, $id, $pid)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ if (! $request->user()) {
|
|
|
|
+ return redirect("/{$pid}");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $group = Group::find($id);
|
|
|
|
+ $cid = $request->user()->profile_id;
|
|
|
|
+
|
|
|
|
+ if (! $group || $group->status) {
|
|
|
|
+ return response()->view('groups.unavailable')->setStatusCode(404);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (! $group->isMember($cid)) {
|
|
|
|
+ return redirect("/{$pid}");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $profile = Profile::whereUsername($pid)->first();
|
|
|
|
+
|
|
|
|
+ if (! $group->isMember($profile->id)) {
|
|
|
|
+ return redirect("/{$pid}");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ($profile) {
|
|
|
|
+ $url = url("/groups/{$id}/user/{$profile->id}");
|
|
|
|
+
|
|
|
|
+ return redirect($url);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ abort(404, 'Invalid username');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupInviteLanding(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort(404, 'Not yet implemented');
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+
|
|
|
|
+ return view('groups.invite', compact('group'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupShortLinkRedirect(Request $request, $hid)
|
|
|
|
+ {
|
|
|
|
+ $gid = HashidService::decode($hid);
|
|
|
|
+ $group = Group::findOrFail($gid);
|
|
|
|
+
|
|
|
|
+ return redirect($group->url());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupInviteClaim(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ $group = GroupService::get($id);
|
|
|
|
+ abort_if(! $group || empty($group), 404);
|
|
|
|
+
|
|
|
|
+ return view('groups.invite-claim', compact('group'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupMemberInviteCheck(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
+
|
|
|
|
+ $exists = GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->exists();
|
|
|
|
+
|
|
|
|
+ return response()->json([
|
|
|
|
+ 'gid' => $id,
|
|
|
|
+ 'can_join' => (bool) $exists,
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupMemberInviteAccept(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
+
|
|
|
|
+ abort_if(! GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->exists(), 422);
|
|
|
|
+
|
|
|
|
+ $gm = new GroupMember;
|
|
|
|
+ $gm->group_id = $id;
|
|
|
|
+ $gm->profile_id = $pid;
|
|
|
|
+ $gm->role = 'member';
|
|
|
|
+ $gm->local_group = $group->local;
|
|
|
|
+ $gm->local_profile = true;
|
|
|
|
+ $gm->join_request = false;
|
|
|
|
+ $gm->save();
|
|
|
|
+
|
|
|
|
+ GroupInvitation::whereGroupId($id)->whereToProfileId($pid)->delete();
|
|
|
|
+ GroupService::del($id);
|
|
|
|
+ GroupService::delSelf($id, $pid);
|
|
|
|
+
|
|
|
|
+ return ['next_url' => $group->url()];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function groupMemberInviteDecline(Request $request, $id)
|
|
|
|
+ {
|
|
|
|
+ abort_if(! $request->user(), 404);
|
|
|
|
+ $pid = $request->user()->profile_id;
|
|
|
|
+ $group = Group::findOrFail($id);
|
|
|
|
+ abort_if($group->isMember($pid), 422, 'Already a member');
|
|
|
|
+
|
|
|
|
+ return ['next_url' => '/'];
|
|
|
|
+ }
|
|
}
|
|
}
|