Passed
Pull Request — master (#244)
by Chenyi
04:13
created

GroupModel::getEloChangeLog()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Models;
4
5
use App\Models\Rating\GroupRatingCalculator;
6
use GrahamCampbell\Markdown\Facades\Markdown;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Support\Facades\DB;
9
use Cache;
10
use Auth;
11
use function GuzzleHttp\json_encode;
12
13
class GroupModel extends Model
14
{
15
    protected $tableName='group';
16
    protected $table='group';
17
    protected $primaryKey='gid';
18
    const DELETED_AT=null;
19
    const UPDATED_AT=null;
20
    const CREATED_AT=null;
21
22
    /*
23
        join_policy:
24
            1:a user can join this group only by invitation
25
            2:a user can join this group only by application
26
            3:a user can join this group by both invitation and application
27
    */
28
    public $role=[
29
        "-3"=>"None",
30
        "-1"=>"Invited",
31
        "0"=>"Pending",
32
        "1"=>"Member",
33
        "2"=>"Manager",
34
        "3"=>"Leader"
35
    ];
36
    public $role_color=[
37
        "-3"=>"wemd-black",
38
        "-1"=>"wemd-deep-purple",
39
        "0"=>"wemd-red",
40
        "1"=>"wemd-grey",
41
        "2"=>"wemd-light-blue",
42
        "3"=>"wemd-amber"
43
    ];
44
45
    public function trendingGroups()
46
    {
47
        return Cache::tags(['group'])->get('trending');
48
    }
49
50
    public function gid($gcode)
51
    {
52
        return DB::table($this->tableName)->where(["gcode"=>$gcode])->first()["gid"];
53
    }
54
55
    public function cacheTrendingGroups()
56
    {
57
        $trending_groups=DB::table($this->tableName)->where(["public"=>1])->orderBy('create_time', 'desc')->select("gid", "gcode", "img", "name", "verified")->get()->all();
58
        foreach ($trending_groups as &$t) {
59
            $t["members"]=$this->countGroupMembers($t["gid"]);
60
        }
61
        usort($trending_groups, function ($a, $b) {
62
            return $b["members"]<=>$a["members"];
63
        });
64
        Cache::tags(['group'])->put('trending', array_slice($trending_groups,0,12), 3600*24);
65
    }
66
67
    public function userGroups($uid)
68
    {
69
        $user_groups=DB::table("group_member")->join("group", "group_member.gid", "=", "group.gid")->where(["uid"=>$uid])->select("group.gid as gid", "gcode", "img", "name", "verified")->limit(12)->get()->all();
70
        foreach ($user_groups as &$m) {
71
            $m["members"]=$this->countGroupMembers($m["gid"]);
72
        }
73
        return $user_groups;
74
    }
75
76
    public function countGroupMembers($gid)
77
    {
78
        return DB::table("group_member")->where(["gid"=>$gid])->count();
79
    }
80
81
    public function getGroupTags($gid)
82
    {
83
        return DB::table("group_tag")->where(["gid"=>$gid])->select("tag")->get()->all();
84
    }
85
86
    public function countGroupContest($gid)
87
    {
88
        return [
89
            "contest_ahead" => DB::table("contest")->where(["gid"=>$gid])->where("begin_time", ">", DB::raw("now()"))->count(),
90
            "contest_going" => DB::table("contest")->where(["gid"=>$gid])->where("begin_time", "<=", DB::raw("now()"))->where("end_time", ">=", DB::raw("now()"))->count(),
91
            "contest_end" => DB::table("contest")->where(["gid"=>$gid])->where("end_time", "<", DB::raw("now()"))->count()
92
        ];
93
    }
94
95
    public function changeNickName($gid, $uid, $nickName)
96
    {
97
        return DB::table("group_member")->where(["gid"=>$gid, "uid"=>$uid])->update([
98
            "nick_name"=>$nickName
99
        ]);
100
    }
101
102
    public function changeGroupName($gid, $GroupName)
103
    {
104
        return DB::table("group")->where('gid',$gid)->update([
105
            "name"=>$GroupName
106
        ]);
107
    }
108
109
    public function changeJoinPolicy($gid, $JoinPolicy){
110
        return DB::table("group")->where('gid',$gid)->update([
111
            "join_policy"=>$JoinPolicy
112
        ]);
113
    }
114
115
    public function details($gcode)
116
    {
117
        $basic_info=DB::table($this->tableName)->where(["gcode"=>$gcode])->first();
118
        if(empty($basic_info)) return [];
119
        $basic_info["members"]=$this->countGroupMembers($basic_info["gid"]);
120
        $basic_info["tags"]=$this->getGroupTags($basic_info["gid"]);
121
        $basic_info["create_time_foramt"]=date_format(date_create($basic_info["create_time"]), 'M jS, Y');
122
        $basic_info["contest_stat"]=$this->countGroupContest($basic_info["gid"]);
123
        return $basic_info;
124
    }
125
126
    public function joinPolicy($gid)
127
    {
128
        $ret=DB::table($this->tableName)->where(["gid"=>$gid])->first();
129
        return empty($ret) ? null : $ret["join_policy"];
130
    }
131
132
    public function userProfile($uid, $gid)
133
    {
134
        $info=DB::table("group_member")
135
        ->join('users','users.id','=','group_member.uid')
136
        ->where(["gid"=>$gid, "uid"=>$uid])
137
        ->where("role", ">", 0)
138
        ->select('avatar','describes','email','gid','uid','name','nick_name','professional_rate','role','sub_group')
139
        ->first();
140
        if (!empty($info)) {
141
            $info["role_parsed"]=$this->role[$info["role"]];
142
            $info["role_color"]=$this->role_color[$info["role"]];
143
        }
144
        return $info;
145
    }
146
147
    public function userList($gid)
148
    {
149
        $user_list=DB::table("group_member")->join(
150
            "users",
151
            "users.id",
152
            "=",
153
            "group_member.uid"
154
        )->where(["gid"=>$gid])->orderBy('role', 'desc')->select(
155
            "role",
156
            "uid",
157
            "name",
158
            "nick_name",
159
            "avatar",
160
            "sub_group",
161
            "ranking"
162
        )->get()->all();
163
        foreach ($user_list as &$u) {
164
            $u["role_parsed"]=$this->role[$u["role"]];
165
            $u["role_color"]=$this->role_color[$u["role"]];
166
            if(is_null($u["sub_group"])) $u["sub_group"]="None";
167
        }
168
        return $user_list;
169
    }
170
171
    public function groupNotice($gid)
172
    {
173
        $notice_item=DB::table("group_notice")->where(["gid"=>$gid])->first();
174
        if (empty($notice_item)) {
175
            return [];
176
        }
177
        $notice_author=DB::table("users")->where(["id"=>$notice_item["uid"]])->first();
178
        $notice_item["name"]=$notice_author["name"];
179
        $notice_item["avatar"]=$notice_author["avatar"];
180
        $notice_item["post_date_parsed"]=$this->formatPostTime($notice_item["post_date"]);
181
        $notice_item["content_parsed"]=clean(convertMarkdownToHtml($notice_item["content"]));
182
        return $notice_item;
183
    }
184
185
    public function judgeClearance($gid, $uid)
186
    {
187
        $ret=DB::table("group_member")->where(["gid"=>$gid, "uid"=>$uid])->first();
188
        return empty($ret) ? -3 : $ret["role"];
189
    }
190
191
    public function changeClearance($uid, $gid, $clearance)
192
    {
193
        return DB::table("group_member")->where([
194
            "uid"=>$uid,
195
            "gid"=>$gid
196
        ])->update([
197
            "role"=>$clearance
198
        ]);
199
    }
200
201
    public function removeClearance($uid, $gid)
202
    {
203
        return DB::table("group_member")->where([
204
            "uid"=>$uid,
205
            "gid"=>$gid
206
        ])->delete();
207
    }
208
209
    public function addClearance($uid, $gid, $clearance)
210
    {
211
        return DB::table("group_member")->insert([
212
            "uid"=>$uid,
213
            "gid"=>$gid,
214
            "role"=>$clearance,
215
            "join_time"=>date("Y-m-d H:i:s")
216
        ]);
217
    }
218
219
    public function isMember($gid, $uid)
220
    {
221
        return DB::table("group_member")->where([
222
            "gid"=> $gid,
223
            "uid"=> $uid
224
        ])->where("role", ">", 0)->count();
225
    }
226
227
    public function problemTags($gid,$pid = -1)
228
    {
229
        if($pid == -1){
230
            $tags =  DB::table('group_problem_tag')
231
            ->select('tag')
232
            ->where('gid',$gid)
233
            ->distinct()
234
            ->get()->all();
235
        }else{
236
            $tags =  DB::table('group_problem_tag')
237
            ->select('tag')
238
            ->where('gid', $gid)
239
            ->where('pid', $pid)
240
            ->distinct()
241
            ->get()->all();
242
        }
243
244
        $tags_arr = [];
245
        if(!empty($tags)){
246
            foreach ($tags as $value) {
247
                array_push($tags_arr,$value['tag']);
248
            }
249
        }
250
        return $tags_arr;
251
    }
252
253
    public function problems($gid)
254
    {
255
        $contestModel = new ContestModel();
256
        $problems = DB::table('contest_problem')
257
        ->join('contest','contest_problem.cid', '=', 'contest.cid')
258
        ->join('problem','contest_problem.pid', '=', 'problem.pid' )
259
        ->select('contest_problem.cid as cid', 'problem.pid as pid', 'pcode', 'title')
260
        ->where('contest.gid',$gid)
261
        ->where('contest.practice',1)
262
        ->orderBy('contest.create_time','desc')
263
        ->distinct()
264
        ->get()->all();
265
        $user_id = Auth::user()->id;
266
        foreach($problems as $key => $value){
267
            if($contestModel->judgeClearance($value['cid'],$user_id) != 3){
268
                unset($problems[$key]);
269
            }else{
270
                $problems[$key]['tags'] = $this->problemTags($gid,$value['pid']);
271
            }
272
        }
273
        return $problems;
274
    }
275
276
    public function problemAddTag($gid,$pid,$tag)
277
    {
278
        return DB::table("group_problem_tag")->insert([
279
            "gid"=>$gid,
280
            "pid"=>$pid,
281
            "tag"=>$tag,
282
        ]);
283
    }
284
285
    public function problemRemoveTag($gid,$pid,$tag)
286
    {
287
        return DB::table("group_problem_tag")->where([
288
            "gid"=>$gid,
289
            "pid"=>$pid,
290
            "tag"=>$tag
291
        ])->delete();
292
    }
293
294
    public function formatPostTime($date)
295
    {
296
        $periods=["second", "minute", "hour", "day", "week", "month", "year", "decade"];
297
        $lengths=["60", "60", "24", "7", "4.35", "12", "10"];
298
299
        $now=time();
300
        $unix_date=strtotime($date);
301
302
        if (empty($unix_date)) {
303
            return "Bad date";
304
        }
305
306
        if ($now>$unix_date) {
307
            $difference=$now-$unix_date;
308
            $tense="ago";
309
        } else {
310
            $difference=$unix_date-$now;
311
            $tense="from now";
312
        }
313
314
        for ($j=0; $difference>=$lengths[$j] && $j<count($lengths)-1; $j++) {
315
            $difference/=$lengths[$j];
316
        }
317
318
        $difference=round($difference);
319
320
        if ($difference!=1) {
321
            $periods[$j].="s";
322
        }
323
324
        return "$difference $periods[$j] {$tense}";
325
    }
326
327
    public function judgeEmailClearance($gid, $email)
328
    {
329
        $user=DB::table("users")->where(["email"=>$email])->first();
330
        if(empty($user)) return -4;
331
        $ret=DB::table("group_member")->where([
332
            "gid"=>$gid,
333
            "uid"=>$user["id"],
334
        ])->first();
335
        return empty($ret) ? -3 : $ret["role"];
336
    }
337
338
    public function inviteMember($gid, $email)
339
    {
340
        $uid=DB::table("users")->where(["email"=>$email])->first();
341
        return DB::table("group_member")->insert([
342
            "uid"=>$uid["id"],
343
            "gid"=>$gid,
344
            "role"=>-1,
345
            "join_time"=>date("Y-m-d H:i:s")
346
        ]);
347
    }
348
349
    public function changeGroup($uid, $gid, $sub)
350
    {
351
        return DB::table("group_member")->where([
352
            "uid"=>$uid,
353
            "gid"=>$gid
354
        ])->update([
355
            "sub_group"=>$sub
356
        ]);
357
    }
358
359
    public function isUser($email)
360
    {
361
        return DB::table("users")->where([
362
            "email"=>$email
363
        ])->count();
364
    }
365
366
    public function isGroup($gcode)
367
    {
368
        return DB::table("group")->where([
369
            "gcode"=>$gcode,
370
        ])->count();
371
    }
372
373
    public function createGroup($uid, $gcode, $img, $name, $public, $description, $join_policy)
374
    {
375
        $gid=DB::table("group")->insertGetId([
376
            "gcode"=>$gcode,
377
            "img"=>$img,
378
            "name"=>$name,
379
            "public"=>$public,
380
            "verified"=>0,
381
            "description"=>$description,
382
            "join_policy"=>$join_policy,
383
            "custom_icon"=>null,
384
            "custom_title"=>null,
385
            "create_time"=>date("Y-m-d H:i:s")
386
        ]);
387
        return DB::table("group_member")->insert([
388
            "uid"=>$uid,
389
            "gid"=>$gid,
390
            "role"=>3,
391
            "join_time"=>date("Y-m-d H:i:s")
392
        ]);
393
    }
394
395
    public function detailNotice($gcode)
396
    {
397
        $group=DB::table("group")->where([
398
            "gcode"=>$gcode,
399
        ])->first();
400
        return $group_notice=DB::table("group_notice")->where([
0 ignored issues
show
Unused Code introduced by
The assignment to $group_notice is dead and can be removed.
Loading history...
401
            "gid"=>$group["gid"],
402
        ])->first();
403
    }
404
405
    public function createNotice($gid, $uid, $title, $content)
406
    {
407
        return DB::table("group_notice")->updateOrInsert(
408
            [
409
                "gid"=>$gid
410
            ],
411
            [
412
                "uid"=>$uid,
413
                "title"=>$title,
414
                "content"=>$content,
415
                "post_date"=>date("Y-m-d H:i:s"),
416
            ]);
417
    }
418
419
    public function groupMemberPracticeContestStat($gid)
420
    {
421
        $contestModel = new ContestModel();
422
423
        $allPracticeContest = DB::table('contest')
424
            ->where([
425
                'gid' => $gid,
426
                'practice' => 1,
427
            ])
428
            ->select('cid','name')
429
            ->get()->all();
430
        $user_list = $this->userList($gid);
431
432
        $memberData = [];
433
        foreach ($user_list as $u) {
434
            $memberData[$u['uid']] = [
435
                'name' => $u['name'],
436
                'nick_name' => $u['nick_name'],
437
                'elo' => $u['ranking'],
438
                'solved_all' => 0,
439
                'problem_all' => 0,
440
                'penalty' => 0,
441
                'contest_detial' => []
442
            ];
443
        }
444
        foreach ($allPracticeContest as $c) {
445
            $contestRankRaw = $contestModel->contestRank($c['cid']);
446
            foreach($contestRankRaw as $key => $contestRank){
447
                if(isset($contestRank['remote']) && $contestRank['remote']){
448
                    unset($contestRankRaw[$key]);
449
                }
450
            }
451
            $contestRank = array_values($contestRankRaw);
452
            $problemsCount = DB::table('contest_problem')
453
                ->where('cid',$c['cid'])
454
                ->count();
455
            $index = 1;
456
            $rank = 1;
457
            $last_cr = [];
458
            $last_rank = 1;
459
            foreach ($contestRank as $cr) {
460
                $last_rank = $index;
461
                if(!empty($last_cr)){
462
                    if($cr['solved'] == $last_cr['solved'] && $cr['penalty'] == $last_cr['penalty'] ){
463
                        $rank = $last_rank;
464
                    }else{
465
                        $rank = $index;
466
                        $last_rank = $rank;
0 ignored issues
show
Unused Code introduced by
The assignment to $last_rank is dead and can be removed.
Loading history...
467
                    }
468
                }
469
                if(in_array($cr['uid'],array_keys($memberData))) {
470
                    $memberData[$cr['uid']]['solved_all'] += $cr['solved'];
471
                    $memberData[$cr['uid']]['problem_all'] += $problemsCount;
472
                    $memberData[$cr['uid']]['penalty'] += $cr['penalty'];
473
                    $memberData[$cr['uid']]['contest_detial'][$c['cid']] = [
474
                        'rank' => $rank,
475
                        'solved' => $cr['solved'],
476
                        'problems' => $problemsCount,
477
                        'penalty' => $cr['penalty']
478
                    ];
479
                }
480
                $last_cr = $cr;
481
                $index++;
482
            }
483
        }
484
        $new_memberData = [];
485
        foreach ($memberData as $uid => $data) {
486
            $contest_count = 0;
487
            $rank_sum = 0;
488
            foreach ($data['contest_detial'] as $cid => $c) {
489
                $rank_sum += $c['rank'];
490
                $contest_count += 1;
491
            }
492
            $temp = $data;
493
            $temp['uid'] = $uid;
494
            if($contest_count != 0){
495
                $temp['rank_ave'] = $rank_sum/$contest_count;
496
            }
497
            array_push($new_memberData,$temp);
498
        }
499
        $ret = [
500
            'contest_list' => $allPracticeContest,
501
            'member_data' => $new_memberData
502
        ];
503
        return $ret;
504
    }
505
506
    public function groupMemberPracticeTagStat($gid)
507
    {
508
        $tags = $this->problemTags($gid);
509
        $tag_problems = [];
510
511
        $user_list = $this->userList($gid);
512
        foreach ($tags as $tag) {
513
            $tag_problems[$tag] = DB::table('problem')
514
                ->join('group_problem_tag','problem.pid','=','group_problem_tag.pid')
515
                ->where([
516
                    'group_problem_tag.gid' => $gid,
517
                    'tag' => $tag
518
                ])
519
                ->select('group_problem_tag.pid as pid','pcode','title')
520
                ->get()->all();
521
        }
522
        $all_problems = [];
523
        foreach ($tag_problems as &$tag_problem_set) {
524
            foreach ($tag_problem_set as $problem) {
525
                $all_problems[$problem['pid']] = $problem;
526
            }
527
            $tag_problem_set = array_column($tag_problem_set,'pid');
528
        }
529
        $submission_data =  DB::table('submission')
530
            ->whereIn('pid',array_keys($all_problems))
531
            ->whereIn('uid',array_column($user_list,'uid'))
532
            ->where('verdict','Accepted')
533
            ->select('pid','uid')
534
            ->get()->all();
535
536
        $memberData = [];
537
        foreach ($user_list as $member) {
538
            $completion = [];
539
            foreach($tag_problems as $tag => $problems) {
540
                $completion[$tag] = [];
541
                foreach ($problems as $problem) {
542
                    $is_accepted = 0;
543
                    foreach ($submission_data as $sd) {
544
                        if($sd['pid'] == $problem && $sd['uid'] == $member['uid']){
545
                            $is_accepted = 1;
546
                            break;
547
                        }
548
                    }
549
                    $completion[$tag][$problem] = $is_accepted;
550
                }
551
            }
552
            array_push($memberData,[
553
                'uid' => $member['uid'],
554
                'name' => $member['name'],
555
                'nick_name' => $member['nick_name'],
556
                'completion' => $completion,
557
            ]);
558
        }
559
        $ret = [
560
            'all_problems' => $all_problems,
561
            'tag_problems' => $tag_problems,
562
            'member_data' => $memberData
563
        ];
564
        return $ret;
565
    }
566
567
    public function refreshElo($gid)
568
    {
569
        DB::table('group_rated_change_log')
570
            ->where('gid',$gid)
571
            ->delete();
572
        DB::table('group_member')
573
            ->where('gid',$gid)
574
            ->update([
575
                'ranking' => 1500
576
            ]);
577
        $contests = DB::table('contest')
578
            ->where([
579
                'gid' => $gid,
580
                'practice' => 1
581
            ])
582
            ->where('end_time','<',date("Y-m-d H:i:s"))
583
            ->select('cid')
584
            ->orderBy('end_time')
585
            ->get()->all();
586
587
        if(empty($contests)) {
588
            return true;
589
        }
590
591
        foreach ($contests as $contest) {
592
            $calc = new GroupRatingCalculator($contest['cid']);
593
            $calc->calculate();
594
            $calc->storage();
595
        }
596
597
        return true;
598
    }
599
600
    public function getEloChangeLog($gid,$uid)
601
    {
602
        return DB::table('group_rated_change_log')
603
            ->join('contest','group_rated_change_log.cid','=','contest.cid')
604
            ->where([
605
                'group_rated_change_log.gid' => $gid,
606
                'group_rated_change_log.uid' => $uid
607
            ])->select('group_rated_change_log.cid as cid', 'contest.name as name', 'ranking')
608
            ->orderBy('contest.end_time')
609
            ->get()->all();
610
    }
611
}
612