Passed
Pull Request — master (#182)
by John
04:04
created

InstallerBase::applyIcon()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 2
eloc 7
nc 2
nop 2
dl 0
loc 10
rs 10
c 2
b 0
f 1
1
<?php
2
3
namespace App\Babel\Install;
4
5
use App\Models\OJModel;
6
use App\Models\CompilerModel;
7
use PharIo\Version\Version;
8
use PharIo\Version\VersionConstraintParser;
9
use PharIo\Version\InvalidVersionException;
10
use Illuminate\Support\Facades\DB;
11
use Exception;
12
13
class InstallerBase
14
{
15
    protected $command;
16
    protected $versionParser;
17
    protected $oid=0;
18
19
    protected function _install($ocode)
20
    {
21
        $this->command->line("Installing <fg=green>$ocode</>");
22
23
        $babelConfig=json_decode(file_get_contents(babel_path("Extension/$ocode/babel.json")),true);
24
25
        // support __cur__ variables
26
        if($babelConfig["version"]=="__cur__") $babelConfig["version"]=explode("-",version())[0];
27
        if($babelConfig["require"]["NOJ"]=="__cur__") $babelConfig["require"]["NOJ"]=explode("-",version())[0];
28
29
        // check version info
30
        if(!isset($babelConfig["version"]) || is_null($babelConfig["version"]) || trim($babelConfig["version"])==""){
31
            $this->command->line("\n  <bg=red;fg=white> Lack version info, aborting. </>\n");
32
            return;
33
        }
34
35
        // check require info
36
        if(!isset($babelConfig["require"]["NOJ"]) || is_null($babelConfig["require"]["NOJ"]) || trim($babelConfig["require"]["NOJ"])==""){
37
            $this->command->line("\n  <bg=red;fg=white> Lack NOJ compability info, aborting. </>\n");
38
            return;
39
        }
40
41
        // check requirement
42
        try {
43
            if(!($this->versionParser->parse($babelConfig["require"]["NOJ"])->complies(new Version(explode("-",version())[0])))){
44
                $this->command->line("Your Current NOJ Version <fg=yellow>".version()."</> doesn't support the following extension: ");
45
                $this->command->line("  - <fg=green>$ocode</> requires NOJ version <fg=yellow>{$babelConfig['require']['NOJ']}</>");
46
                return;
47
            }
48
        } catch(InvalidVersionException $e) {
49
            $this->command->line("\n  <bg=red;fg=white> Illegal Compability Info, aborting. </>\n");
50
            return;
51
        }
52
53
        DB::beginTransaction();
54
55
        // get current installed version info
56
        $info=OJModel::basic(OJModel::oid($ocode));
57
58
        // if there isn't, create one
59
        if(empty($info)){
60
            $this->oid=OJModel::insertOJ([
61
                "ocode"=>$babelConfig["code"],
62
                "name"=>$babelConfig["name"],
63
                "home_page"=>$babelConfig["website"],
64
                "logo"=>"/static/img/oj/default.png",
65
                "status"=>1,
66
                "version"=>"",
67
                "compiler_timestamp"=>"",
68
            ]);
69
        } else {
70
            // check legal version format
71
            try {
72
                $currentVersion=new Version($babelConfig["version"]);
73
            } catch(InvalidVersionException $e) {
74
                DB::rollback();
75
                $this->command->line("\n  <bg=red;fg=white> Illegal Version Info, aborting. </>\n");
76
                return;
77
            }
78
79
            // check there is a not null version
80
            if(isset($info["version"]) && !is_null($info["version"]) && trim($info["version"])!=""){
81
                try {
82
                    $installedVersion=new Version($info["version"]);
83
                } catch(InvalidVersionException $e) {
84
                    DB::rollback();
85
                    $this->command->line("\n  <bg=red;fg=white> Illegal Version Info, aborting. </>\n");
86
                    return;
87
                }
88
89
                if (!($currentVersion->isGreaterThan($installedVersion))) {
90
                    // lower version or even
91
                    DB::rollback();
92
                    $this->command->line("Nothing to install or update");
93
                    return;
94
                }
95
            }
96
97
            $this->oid=$info["oid"];
98
        }
99
100
        // retrieve compiler config and then import it
101
        $installed_timestamp=0;
102
        if(isset($info["compiler_timestamp"]) && !is_null($info["compiler_timestamp"]) && trim($info["compiler_timestamp"])!=""){
103
            $installed_timestamp=intval($info["compiler_timestamp"]);
104
        }
105
        $ConpilerConfig = glob(babel_path("Extension/$ocode/compiler/*.*"));
106
        foreach($ConpilerConfig as $file) {
107
            if(intval(basename($file)) > $installed_timestamp) {
108
                try {
109
                    $this->commitCompiler($file,json_decode(file_get_contents($file), true));
110
                } catch (Exception $e) {
111
                    DB::rollback();
112
                    $this->command->line("<fg=red>Error:     ".$e->getMessage()."</>");
113
                    $this->command->line("\n  <bg=red;fg=white> Compiler info import failure, aborting. </>\n");
114
                    return;
115
                }
116
            }
117
        }
118
119
        // import css
120
        try {
121
            if (isset($babelConfig["custom"]["css"]) && !is_null($babelConfig["custom"]["css"]) && trim($babelConfig["custom"]["css"])!="") {
122
                $cssPath=babel_path("Extension/$ocode/".$babelConfig["custom"]["css"]);
123
            }else{
124
                $cssPath=null;
125
            }
126
            $this->applyCustom($ocode, $cssPath);
127
        }catch(Exception $e){
128
            DB::rollback();
129
            $this->command->line("\n  <bg=red;fg=white> Unable to add an custom css for this extension, aborting. </>\n");
130
            return;
131
        }
132
133
134
        // import icon
135
        try{
136
            $imgPath=babel_path("Extension/$ocode/".$babelConfig["icon"]);
137
            $storePath=$this->applyIcon($ocode, $imgPath);
138
            OJModel::updateOJ($this->oid,["logo"=>$storePath]);
139
        }catch(Exception $e){
140
            DB::rollback();
141
            $this->command->line("\n  <bg=red;fg=white> Unable to add an icon for this extension, aborting. </>\n");
142
            return;
143
        }
144
145
        DB::commit();
146
    }
147
148
    protected function _uninstall($ocode)
149
    {
150
        $this->command->line("<fg=red>Warning: Removing an installed and already-used extension may cause severe consequences, including lossing user submission, problem data and contests regaring or involving the usage of this extension. </>");
151
        if ($this->command->confirm("Are you sure you want to uninstall $ocode?")){
152
            //uninstall
153
            OJModel::removeOJ(["ocode"=>$ocode]);
154
            $this->command->line("Already removed <fg=green>$ocode</>");
155
        }
156
    }
157
158
    public function __construct($class)
159
    {
160
        $this->command=$class;
161
        $this->versionParser = new VersionConstraintParser();
162
    }
163
164
165
    protected function commitCompiler($path,$json)
166
    {
167
        $this->command->line("<fg=yellow>Migrating: </>$path");
168
        $modifications=$json["modifications"];
169
        foreach($modifications as $m){
170
            if($m["method"]=="add"){
171
                CompilerModel::add([
172
                    "oid"=>$this->oid,
173
                    "comp"=>$m["compability"],
174
                    "lang"=>$m["language"],
175
                    "lcode"=>$m["code"],
176
                    "icon"=>$m["icon"],
177
                    "display_name"=>$m["display"],
178
                    "available"=>1,
179
                    "deleted"=>0
180
                ]);
181
            }elseif($m["method"]=="modify"){
182
                $modifyItem=[];
183
                if(isset($m["compability"])) $modifyItem["comp"]=$m["compability"];
184
                if(isset($m["language"])) $modifyItem["lang"]=$m["language"];
185
                if(isset($m["icon"])) $modifyItem["icon"]=$m["icon"];
186
                if(isset($m["display"])) $modifyItem["display_name"]=$m["display"];
187
                CompilerModel::modify([
188
                    "oid"=>$this->oid,
189
                    "lcode"=>$m["code"],
190
                ], $modifyItem);
191
            }elseif($m["method"]=="remove"){
192
                CompilerModel::remove([
193
                    "oid"=>$this->oid,
194
                    "lcode"=>$m["code"],
195
                ]);
196
            }else{
197
                continue;
198
            }
199
        }
200
        $this->command->line("<fg=green>Migrated:  </>$path");
201
    }
202
203
    protected function applyIcon($ocode, $imgPath)
204
    {
205
        $storePath=base_path("public/static/img/oj/$ocode/");
206
        if(is_dir($storePath)) {
207
            $this->delFile($storePath);
208
        }else{
209
            mkdir($storePath);
210
        }
211
        file_put_contents($storePath.basename($imgPath),file_get_contents($imgPath));
212
        return "/static/img/oj/$ocode/".basename($imgPath);
213
    }
214
215
    protected function applyCustom($ocode, $cssPath)
216
    {
217
        $storePath=base_path("public/static/css/oj/");
218
        if(!is_dir($storePath)) {
219
            mkdir($storePath);
220
        }
221
        if (is_null($cssPath)) {
222
            file_put_contents($storePath."$ocode.css", "\/*Silence is Golden*\/");
223
        }else {
224
            file_put_contents($storePath."$ocode.css", file_get_contents($cssPath));
225
        }
226
    }
227
228
    private function delFile($dirName){
229
        if(file_exists($dirName) && $handle=opendir($dirName)){
230
            while(false!==($item = readdir($handle))){
231
                if($item!= "." && $item != ".."){
232
                    if(file_exists($dirName.'/'.$item) && is_dir($dirName.'/'.$item)){
233
                        delFile($dirName.'/'.$item);
0 ignored issues
show
Bug introduced by
The function delFile was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

233
                        /** @scrutinizer ignore-call */ 
234
                        delFile($dirName.'/'.$item);
Loading history...
234
                    }else{
235
                        if(unlink($dirName.'/'.$item)){
236
                            return true;
237
                        }
238
                    }
239
                }
240
            }
241
            closedir( $handle);
242
        }
243
    }
244
}
245