LJSUP-17669: Login.bml form refactoring
[livejournal.git] / cgi-bin / ljrelation.pl
blob07b54f74d974606b146acc46de050ec5f6bb16e2
1 package LJ;
3 use strict;
4 use warnings;
6 # Internal modules
7 use LJ::User::Groups;
8 use LJ::RelationService;
10 #########################
11 # Types of relations:
12 # P - poster
13 # A - maintainer
14 # B - ban
15 # N - pre-approved
16 # M - moderator
17 # S - supermaintainer
18 # I - inviter
19 # D - spammer
20 # W - journal sweeper
21 # C - do not receive mass mailing from community
22 # J - ban in journalpromo
23 # R - subscriber
24 # F - friend
25 #########################
27 # <LJFUNC>
28 # name: LJ::is_friend
29 # des: Checks to see if a user is a friend of another user.
30 # returns: boolean; 1 if user B is a friend of user A or if A == B
31 # args: usera, userb
32 # des-usera: Source user hashref or userid.
33 # des-userb: Destination user hashref or userid. (can be undef)
34 # </LJFUNC>
35 sub is_friend {
36 my ($ua, $ub) = @_[0, 1];
38 $ua = LJ::want_user($ua);
39 $ub = LJ::want_user($ub);
41 return 0 unless $ua && $ub;
42 return 1 if $ua == $ub;
44 if (LJ::is_enabled('new_friends_and_subscriptions')) {
45 my $res1 = LJ::RelationService->is_relation_to($ua, $ub, 'F');
47 if ($ua->is_community) {
48 return $res1;
51 my $res2 = LJ::RelationService->is_relation_to($ub, $ua, 'F');
53 return $res1 && $res2 ? 1 : 0;
56 # get group mask from the first argument to the second argument and
57 # see if first bit is set. if it is, they're a friend. get_groupmask
58 # is memcached and used often, so it's likely to be available quickly.
59 return LJ::get_groupmask(@_[0, 1]) & 1;
62 # <LJFUNC>
63 # name: LJ::is_banned
64 # des: Checks to see if a user is banned from a journal.
65 # returns: boolean; 1 if "user" is banned from "journal"
66 # args: user, journal
67 # des-user: User hashref or userid.
68 # des-journal: Journal hashref or userid.
69 # </LJFUNC>
70 sub is_banned {
71 # get user and journal ids
72 my $uid = LJ::want_userid(shift);
73 my $jid = LJ::want_userid(shift);
75 return 1 unless $uid && $jid;
76 return 0 if $uid == $jid;
78 # edge from journal -> user
79 return LJ::check_rel($jid, $uid, 'B');
82 sub get_groupmask {
83 my ($journal, $remote) = @_;
84 return 0 unless $journal && $remote;
86 $remote = LJ::want_user($remote);
87 $journal = LJ::want_user($journal);
89 if (LJ::is_enabled('new_friends_and_subscriptions')) {
90 if (my $groupmask = LJ::RelationService->get_groupmask($journal, $remote)) {
91 return $groupmask + 0;
94 if (my $groupmask = LJ::User::Groups->get_groupmask($journal, $remote)) {
95 return $groupmask + 0;
98 return 0;
101 return LJ::RelationService->get_groupmask($journal, $remote) + 0;
104 # <LJFUNC>
105 # name: LJ::load_rel_user
106 # des: Load user relationship information. Loads all relationships of type 'type' in
107 # which user 'userid' participates on the left side (is the source of the
108 # relationship).
109 # args: db?, userid, type
110 # des-userid: userid or a user hash to load relationship information for.
111 # des-type: type of the relationship
112 # returns: reference to an array of userids
113 # </LJFUNC>
114 sub load_rel_user {
115 my $db = isdb($_[0]) ? shift : undef;
116 my ($u, $type, %args) = @_;
118 return undef unless $u and $type;
120 my $limit = int(delete $args{limit} || 50000);
122 my @uids = LJ::RelationService->find_relation_destinations($u, $type, limit => $limit, db => $db, %args);
123 return \@uids;
126 # <LJFUNC>
127 # name: LJ::load_rel_user_cache
128 # des: Loads user relationship information of the type 'type' where user
129 # 'targetid' participates on the left side (is the source of the relationship)
130 # trying memcache first. The results from this sub should be
131 # <strong>treated as inaccurate and out of date</strong>.
132 # args: userid, type
133 # des-userid: userid or a user hash to load relationship information for.
134 # des-type: type of the relationship
135 # returns: reference to an array of userids
136 # </LJFUNC>
137 sub load_rel_user_cache {
138 my ($userid, $type) = @_;
139 return undef unless $type && $userid;
141 my $u = LJ::want_user($userid);
142 return undef unless $u;
144 return LJ::load_rel_user($u, $type);
147 # <LJFUNC>
148 # name: LJ::load_rel_target
149 # des: Load user relationship information. Loads all relationships of type 'type' in
150 # which user 'targetid' participates on the right side (is the target of the
151 # relationship).
152 # args: db?, targetid, type
153 # des-targetid: userid or a user hash to load relationship information for.
154 # des-type: type of the relationship
155 # returns: reference to an array of userids
156 # </LJFUNC>
157 sub load_rel_target {
158 my $db = isdb($_[0]) ? shift : undef;
159 my ($u, $type, %args) = @_;
161 return undef unless $u and $type;
163 my $limit = int(delete $args{limit} || 50000);
165 my @uids = LJ::RelationService->find_relation_sources($u, $type, limit => $limit, db => $db, %args);
166 return \@uids;
169 # <LJFUNC>
170 # name: LJ::_get_rel_memcache
171 # des: Helper function: returns memcached value for a given (userid, targetid, type) triple, if valid.
172 # args: userid, targetid, type
173 # des-userid: source userid, nonzero
174 # des-targetid: target userid, nonzero
175 # des-type: type (reluser) or typeid (rel2) of the relationship
176 # returns: undef on failure, 0 or 1 depending on edge existence
177 # </LJFUNC>
178 sub _get_rel_memcache {
179 return undef unless @LJ::MEMCACHE_SERVERS;
180 return undef if $LJ::DISABLED{memcache_reluser};
182 my ($userid, $targetid, $type) = @_;
183 return undef unless $userid && $targetid && defined $type;
185 # memcache keys
186 my $relkey = [$userid, "rel:$userid:$targetid:$type"]; # rel $uid->$targetid edge
187 my $modukey = [$userid, "relmodu:$userid:$type" ]; # rel modtime for uid
188 my $modtkey = [$targetid, "relmodt:$targetid:$type" ]; # rel modtime for targetid
190 # do a get_multi since $relkey and $modukey are both hashed on $userid
191 my $memc = LJ::MemCacheProxy::get_multi($relkey, $modukey);
192 return undef unless $memc && ref $memc eq 'HASH';
194 # [{0|1}, modtime]
195 my $rel = $memc->{$relkey->[1]};
196 return undef unless $rel && ref $rel eq 'ARRAY';
198 # check rel modtime for $userid
199 my $relmodu = $memc->{$modukey->[1]};
200 return undef if ! $relmodu || $relmodu > $rel->[1];
202 # check rel modtime for $targetid
203 my $relmodt = LJ::MemCacheProxy::get($modtkey);
204 return undef if ! $relmodt || $relmodt > $rel->[1];
206 # return memcache value if it's up-to-date
207 return $rel->[0] ? 1 : 0;
210 # <LJFUNC>
211 # name: LJ::_set_rel_memcache
212 # des: Helper function: sets memcache values for a given (userid, targetid, type) triple
213 # args: userid, targetid, type
214 # des-userid: source userid, nonzero
215 # des-targetid: target userid, nonzero
216 # des-type: type (reluser) or typeid (rel2) of the relationship
217 # returns: 1 on success, undef on failure
218 # </LJFUNC>
219 sub _set_rel_memcache {
220 return 1 unless @LJ::MEMCACHE_SERVERS;
222 my ($userid, $targetid, $type, $val) = @_;
223 return undef unless $userid && $targetid && defined $type;
224 $val = $val ? 1 : 0;
226 # memcache keys
227 my $relkey = [$userid, "rel:$userid:$targetid:$type"]; # rel $uid->$targetid edge
228 my $modukey = [$userid, "relmodu:$userid:$type" ]; # rel modtime for uid
229 my $modtkey = [$targetid, "relmodt:$targetid:$type" ]; # rel modtime for targetid
231 my $now = time();
232 my $exp = $now + 3600*6; # 6 hour
234 LJ::MemCacheProxy::set($relkey, [$val, $now], $exp);
235 LJ::MemCacheProxy::set($modukey, $now, $exp);
236 LJ::MemCacheProxy::set($modtkey, $now, $exp);
238 return 1;
241 # <LJFUNC>
242 # name: LJ::check_rel
243 # des: Checks whether two users are in a specified relationship to each other.
244 # args: db?, userid, targetid, type
245 # des-userid: source userid, nonzero; may also be a user hash.
246 # des-targetid: target userid, nonzero; may also be a user hash.
247 # des-type: type of the relationship
248 # returns: 1 if the relationship exists, 0 otherwise
249 # </LJFUNC>
250 sub check_rel {
251 my ($userid, $targetid, $type) = @_;
252 return undef unless $type && $userid && $targetid;
254 my $result;
255 if ( ref $type eq 'ARRAY' ) {
256 $result = LJ::RelationService->is_relation_type_to($userid, $targetid, $type);
257 } else {
258 $result = LJ::RelationService->is_relation_to($userid, $targetid, $type);
260 return $result;
263 # <LJFUNC>
264 # name: LJ::set_rel
265 # des: Sets relationship information for two users.
266 # args: dbs?, userid, targetid, type
267 # des-dbs: Deprecated; optional, a master/slave set of database handles.
268 # des-userid: source userid, or a user hash
269 # des-targetid: target userid, or a user hash
270 # des-type: type of the relationship
271 # returns: 1 if set succeeded, otherwise undef
272 # </LJFUNC>
273 sub set_rel {
274 my ($userid, $targetid, $type) = @_;
276 return LJ::RelationService->create_relation_to($userid, $targetid, $type);
279 # <LJFUNC>
280 # name: LJ::set_rel_multi
281 # des: Sets relationship edges for lists of user tuples.
282 # args: edges
283 # des-edges: array of arrayrefs of edges to set: [userid, targetid, type].
284 # Where:
285 # userid: source userid, or a user hash;
286 # targetid: target userid, or a user hash;
287 # type: type of the relationship.
288 # returns: 1 if all sets succeeded, otherwise undef
289 # </LJFUNC>
290 sub set_rel_multi {
291 return LJ::RelationService->set_rel_multi( \@_ );
294 # <LJFUNC>
295 # name: LJ::clear_rel_multi
296 # des: Clear relationship edges for lists of user tuples.
297 # args: edges
298 # des-edges: array of arrayrefs of edges to clear: [userid, targetid, type].
299 # Where:
300 # userid: source userid, or a user hash;
301 # targetid: target userid, or a user hash;
302 # type: type of the relationship.
303 # returns: 1 if all clears succeeded, otherwise undef
304 # </LJFUNC>
305 sub clear_rel_multi {
306 return LJ::RelationService->clear_rel_multi( \@_ );
309 # <LJFUNC>
310 # name: LJ::clear_rel
311 # des: Deletes a relationship between two users or all relationships of a particular type
312 # for one user, on either side of the relationship.
313 # info: One of userid,targetid -- bit not both -- may be '*'. In that case,
314 # if, say, userid is '*', then all relationship edges with target equal to
315 # targetid and of the specified type are deleted.
316 # If both userid and targetid are numbers, just one edge is deleted.
317 # args: dbs?, userid, targetid, type
318 # des-dbs: Deprecated; optional, a master/slave set of database handles.
319 # des-userid: source userid, or a user hash, or '*'
320 # des-targetid: target userid, or a user hash, or '*'
321 # des-type: type of the relationship
322 # returns: 1 if clear succeeded, otherwise undef
323 # </LJFUNC>
324 sub clear_rel {
325 my ($userid, $targetid, $type) = @_;
326 return undef if $userid eq '*' and $targetid eq '*';
328 my $u;
329 $u = LJ::want_user($userid) unless $userid eq '*';
330 $userid = LJ::want_userid($userid) unless $userid eq '*';
331 $targetid = LJ::want_userid($targetid) unless $targetid eq '*';
332 return undef unless $type && $userid && $targetid;
334 my $result = LJ::RelationService->remove_relation_to($userid, $targetid, $type);
335 return undef unless $result;
339 return 1;