123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- <?php
- namespace App\Services;
- use App\Profile;
- use App\Models\Group;
- use App\Models\GroupCategory;
- use App\Models\GroupMember;
- use App\Models\GroupPost;
- use App\Models\GroupInteraction;
- use App\Models\GroupLimit;
- use App\Util\ActivityPub\Helpers;
- use Cache;
- use Purify;
- use App\Http\Resources\Groups\GroupResource;
- class GroupService
- {
- const CACHE_KEY = 'pf:services:groups:';
- protected static function key($name)
- {
- return self::CACHE_KEY . $name;
- }
- public static function get($id, $pid = false)
- {
- $res = Cache::remember(
- self::key($id),
- 1209600,
- function() use($id, $pid) {
- $group = (new Group)->withoutRelations()->whereNull('status')->find($id);
- if(!$group) {
- return null;
- }
- $admin = $group->profile_id ? AccountService::get($group->profile_id) : null;
- return [
- 'id' => (string) $group->id,
- 'name' => $group->name,
- 'description' => $group->description,
- 'short_description' => str_limit(strip_tags($group->description), 120),
- 'category' => self::categoryById($group->category_id),
- 'local' => (bool) $group->local,
- 'url' => $group->url(),
- 'shorturl' => url('/g/'.HashidService::encode($group->id)),
- 'membership' => $group->getMembershipType(),
- 'member_count' => $group->members()->whereJoinRequest(false)->count(),
- 'verified' => false,
- 'self' => null,
- 'admin' => $admin,
- 'config' => [
- 'recommended' => (bool) $group->recommended,
- 'discoverable' => (bool) $group->discoverable,
- 'activitypub' => (bool) $group->activitypub,
- 'is_nsfw' => (bool) $group->is_nsfw,
- 'dms' => (bool) $group->dms
- ],
- 'metadata' => $group->metadata,
- 'created_at' => $group->created_at->toAtomString(),
- ];
- }
- );
- if($pid) {
- $res['self'] = self::getSelf($id, $pid);
- }
- return $res;
- }
- public static function del($id)
- {
- Cache::forget('ap:groups:object:' . $id);
- return Cache::forget(self::key($id));
- }
- public static function getSelf($gid, $pid)
- {
- return Cache::remember(
- self::key('self:gid-' . $gid . ':pid-' . $pid),
- 3600,
- function() use($gid, $pid) {
- $group = Group::find($gid);
- if(!$gid || !$pid) {
- return [
- 'is_member' => false,
- 'role' => null,
- 'is_requested' => null
- ];
- }
- return [
- 'is_member' => $group->isMember($pid),
- 'role' => $group->selfRole($pid),
- 'is_requested' => optional($group->members()->whereProfileId($pid)->first())->join_request ?? false
- ];
- }
- );
- }
- public static function delSelf($gid, $pid)
- {
- Cache::forget(self::key("is_member:{$gid}:{$pid}"));
- return Cache::forget(self::key('self:gid-' . $gid . ':pid-' . $pid));
- }
- public static function sidToGid($gid, $pid)
- {
- return Cache::remember(self::key('s2gid:' . $gid . ':' . $pid), 3600, function() use($gid, $pid) {
- return optional(GroupPost::whereGroupId($gid)->whereStatusId($pid)->first())->id;
- });
- }
- public static function membershipsByPid($pid)
- {
- return Cache::remember(self::key("mbpid:{$pid}"), 3600, function() use($pid) {
- return GroupMember::whereProfileId($pid)->pluck('group_id');
- });
- }
- public static function config()
- {
- return [
- 'enabled' => config('exp.gps') ?? false,
- 'limits' => [
- 'group' => [
- 'max' => 999,
- 'federation' => false,
- ],
- 'user' => [
- 'create' => [
- 'new' => true,
- 'max' => 10
- ],
- 'join' => [
- 'max' => 10
- ],
- 'invite' => [
- 'max' => 20
- ]
- ]
- ],
- 'guest' => [
- 'public' => false
- ]
- ];
- }
- public static function fetchRemote($url)
- {
- // todo: refactor this demo
- $res = Helpers::fetchFromUrl($url);
- if(!$res || !isset($res['type']) || $res['type'] != 'Group') {
- return false;
- }
- $group = Group::whereRemoteUrl($url)->first();
- if($group) {
- return $group;
- }
- $group = new Group;
- $group->remote_url = $res['url'];
- $group->name = $res['name'];
- $group->inbox_url = $res['inbox'];
- $group->metadata = [
- 'header' => [
- 'url' => $res['icon']['image']['url']
- ]
- ];
- $group->description = Purify::clean($res['summary']);
- $group->local = false;
- $group->save();
- return $group->url();
- }
- public static function log(
- string $groupId,
- string $profileId,
- string $type = null,
- array $meta = null,
- string $itemType = null,
- string $itemId = null
- )
- {
- // todo: truncate (some) metadata after XX days in cron/queue
- $log = new GroupInteraction;
- $log->group_id = $groupId;
- $log->profile_id = $profileId;
- $log->type = $type;
- $log->item_type = $itemType;
- $log->item_id = $itemId;
- $log->metadata = $meta;
- $log->save();
- }
- public static function getRejoinTimeout($gid, $pid)
- {
- $key = self::key('rejoin-timeout:gid-' . $gid . ':pid-' . $pid);
- return Cache::has($key);
- }
- public static function setRejoinTimeout($gid, $pid)
- {
- // todo: allow group admins to manually remove timeout
- $key = self::key('rejoin-timeout:gid-' . $gid . ':pid-' . $pid);
- return Cache::put($key, 1, 86400);
- }
- public static function getMemberInboxes($id)
- {
- // todo: cache this, maybe add join/leave methods to this service to handle cache invalidation
- $group = (new Group)->withoutRelations()->findOrFail($id);
- if(!$group->local) {
- return [];
- }
- $members = GroupMember::whereGroupId($id)->whereLocalProfile(false)->pluck('profile_id');
- return Profile::find($members)->map(function($u) {
- return $u->sharedInbox ?? $u->inbox_url;
- })->toArray();
- }
- public static function getInteractionLimits($gid, $pid)
- {
- return Cache::remember(self::key(":il:{$gid}:{$pid}"), 3600, function() use($gid, $pid) {
- $limit = GroupLimit::whereGroupId($gid)->whereProfileId($pid)->first();
- if(!$limit) {
- return [
- 'limits' => [
- 'can_post' => true,
- 'can_comment' => true,
- 'can_like' => true
- ],
- 'updated_at' => null
- ];
- }
- return [
- 'limits' => $limit->limits,
- 'updated_at' => $limit->updated_at->format('c')
- ];
- });
- }
- public static function clearInteractionLimits($gid, $pid)
- {
- return Cache::forget(self::key(":il:{$gid}:{$pid}"));
- }
- public static function canPost($gid, $pid)
- {
- $limits = self::getInteractionLimits($gid, $pid);
- if($limits) {
- return (bool) $limits['limits']['can_post'];
- } else {
- return true;
- }
- }
- public static function canComment($gid, $pid)
- {
- $limits = self::getInteractionLimits($gid, $pid);
- if($limits) {
- return (bool) $limits['limits']['can_comment'];
- } else {
- return true;
- }
- }
- public static function canLike($gid, $pid)
- {
- $limits = self::getInteractionLimits($gid, $pid);
- if($limits) {
- return (bool) $limits['limits']['can_like'];
- } else {
- return true;
- }
- }
- public static function categories($onlyActive = true)
- {
- return Cache::remember(self::key(':categories'), 2678400, function() use($onlyActive) {
- return GroupCategory::when($onlyActive, function($q, $onlyActive) {
- return $q->whereActive(true);
- })
- ->orderBy('order')
- ->pluck('name')
- ->toArray();
- });
- }
- public static function categoryById($id)
- {
- return Cache::remember(self::key(':categorybyid:'.$id), 2678400, function() use($id) {
- $category = GroupCategory::find($id);
- if($category) {
- return [
- 'name' => $category->name,
- 'url' => url("/groups/explore/category/{$category->slug}")
- ];
- }
- return false;
- });
- }
- public static function isMember($gid = false, $pid = false)
- {
- if(!$gid || !$pid) {
- return false;
- }
- $key = self::key("is_member:{$gid}:{$pid}");
- return Cache::remember($key, 3600, function() use($gid, $pid) {
- return GroupMember::whereGroupId($gid)
- ->whereProfileId($pid)
- ->whereJoinRequest(false)
- ->exists();
- });
- }
- public static function mutualGroups($cid = false, $pid = false, $exclude = [])
- {
- if(!$cid || !$pid) {
- return [
- 'count' => 0,
- 'groups' => []
- ];
- }
- $self = self::membershipsByPid($cid);
- $user = self::membershipsByPid($pid);
- if(!$self->count() || !$user->count()) {
- return [
- 'count' => 0,
- 'groups' => []
- ];
- }
- $intersect = $self->intersect($user);
- $count = $intersect->count();
- $groups = $intersect
- ->values()
- ->filter(function($id) use($exclude) {
- return !in_array($id, $exclude);
- })
- ->shuffle()
- ->take(1)
- ->map(function($id) {
- return self::get($id);
- });
- return [
- 'count' => $count,
- 'groups' => $groups
- ];
- }
- }
|