UpdateSiteProposals.php 5.16 KB
Newer Older
1 2 3 4 5 6
<?php

namespace App\Console\Commands;

use App\Project;
use Illuminate\Console\Command;
7 8
use GitLab\Connection;
use GuzzleHttp\Client;
9 10 11 12 13 14 15 16 17 18
use stdClass;
use Symfony\Component\Yaml\Yaml;

class UpdateSiteProposals extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
xiphon's avatar
xiphon committed
19
    protected $signature = 'proposal:update';
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Update the files required for jeykll site';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     */
    public function handle()
    {
43 44
        $response = [
            $this->ideaProposals(),
45 46
            $this->getProposals('Funding Required', 'FUNDING-REQUIRED'),
            $this->getProposals('Work in Progress', 'WORK-IN-PROGRESS'),
47 48
        ];
        $json = json_encode($response, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
xiphon's avatar
xiphon committed
49
        \Storage::put('proposals.json', $json);
50 51 52 53 54 55

        $response = [
            $this->getProposals('Completed Proposals', 'COMPLETED'),
        ];
        $json = json_encode($response, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
        \Storage::put('complete.json', $json);
56 57
    }

xiphon's avatar
xiphon committed
58 59 60 61 62 63 64 65
    private function sortProposalsByDateDesc($responseProposals)
    {
        usort($responseProposals, function($a, $b){
            return strtotime($a->date) < strtotime($b->date) ? 1 : -1;
        });
        return $responseProposals;
    }

66
    private function ideaProposals()
67
    {
68 69
        $group = new stdClass();
        $group->stage = 'Ideas';
70
        $responseProposals = [];
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

        $ideas = [];
        $connection = new Connection(new Client());
        $mergeRequests = $connection->mergeRequests('opened');
        foreach ($mergeRequests as $mergeRequest) {
            $newFiles = $connection->getNewFiles($mergeRequest->iid);
            if (sizeof($newFiles) != 1) {
                $this->error ("Skipping MR #$mergeRequest->id '$mergeRequest->title': contains multiple files");
                continue;
            }
            $filename = $newFiles[0];
            if (!preg_match('/.+\.md$/', $filename)) {
                $this->error("Skipping MR #$mergeRequest->id '$mergeRequest->title': doesn't contain any .md file");
                continue;
            }
            if (basename($filename) != $filename) {
                $this->error("Skipping MR #$mergeRequest->id '$mergeRequest->title': $filename must be in the root folder");
                continue;
xiphon's avatar
xiphon committed
89
            }
90 91 92 93 94 95 96 97 98 99 100
            if (in_array($filename, $ideas)) {
                $this->error("Skipping MR #$mergeRequest->id '$mergeRequest->title': duplicated $filename, another MR #$ideas[$filename]->id");
                continue;
            }
            $project = Project::where('filename', $filename)->first();
            if ($project) {
                $this->error("Skipping MR #$mergeRequest->id '$mergeRequest->title': already have a project $filename");
                continue;
            }
            $this->info("Idea MR #$mergeRequest->id '$mergeRequest->title': $filename");

101
            $prop = new stdClass();
102 103 104 105
            $prop->name = htmlspecialchars(trim($mergeRequest->title), ENT_QUOTES);
            $prop->{'gitlab-url'} = htmlspecialchars($mergeRequest->web_url, ENT_QUOTES);
            $prop->author = htmlspecialchars($mergeRequest->author->username, ENT_QUOTES);
            $prop->date = date('F j, Y', strtotime($mergeRequest->created_at));
106 107
            $responseProposals[] = $prop;
        }
108

xiphon's avatar
xiphon committed
109
        $group->proposals = $this->sortProposalsByDateDesc($responseProposals);
110 111 112
        return $group;
    }

113
    private function formatProposal($proposal)
114
    {
115 116
        $prop = new stdClass();
        $prop->name = $proposal->title;
117
        $prop->{'donate-url'} = url("projects/{$proposal->subaddr_index}/donate");
118
        $prop->{'gitlab-url'} = $proposal->gitlab_url;
xiphon's avatar
xiphon committed
119
        $prop->{'local-url'} = '/proposals/'. pathinfo($proposal->filename, PATHINFO_FILENAME) . '.html';
120
        $prop->contributions = $proposal->contributions;
121 122 123 124 125 126 127 128 129 130
        $prop->milestones = $proposal->milestones;
        $prop->{'milestones-completed'} = $proposal->milestones_completed;
        $milestones_percentage = min(100, (int)(($proposal->milestones_completed * 100) / $proposal->milestones));
        $prop->{'milestones-percentage'} = $milestones_percentage;
        $prop->percentage = $proposal->percentage_funded;
        $prop->amount = $proposal->target_amount;
        $prop->{'amount-funded'} = $proposal->amount_received;
        $prop->author = $proposal->author;
        $prop->date = $proposal->created_at->format('F j, Y');
        return $prop;
131 132
    }

133
    private function getProposals($stage, $state)
134 135
    {
        $group = new stdClass();
136
        $group->stage = $stage;
137
        $responseProposals = [];
138
        $proposals = Project::where('state', $state)->get();
139
        foreach ($proposals as $proposal) {
140
            $responseProposals[] = $this->formatProposal($proposal);
141
        }
xiphon's avatar
xiphon committed
142
        $group->proposals = $this->sortProposalsByDateDesc($responseProposals);
143
        return $group;
144 145
    }
}