Passed
Push — 1.11.x ( 680d76...6673eb )
by
unknown
13:22 queued 51s
created

AnswerInOfficeDoc::return_header()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 10
rs 10
cc 1
nc 1
nop 3
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
/**
6
 * Class AnswerInOfficeDoc
7
 * Allows a question type where the answer is written in an Office document.
8
 *
9
 * @author Cristian
10
 */
11
class AnswerInOfficeDoc extends Question
12
{
13
    public $typePicture = 'options_evaluation.png';
14
    public $explanationLangVar = 'AnswerInOfficeDoc';
15
    public $sessionId;
16
    public $userId;
17
    public $exerciseId;
18
    public $exeId;
19
    private $storePath;
20
    private $fileName;
21
    private $filePath;
22
23
    /**
24
     * Constructor.
25
     */
26
    public function __construct()
27
    {
28
        if ('true' !== OnlyofficePlugin::create()->get('enable_onlyoffice_plugin')) {
29
            throw new Exception(get_lang('OnlyOfficePluginRequired'));
30
        }
31
32
        parent::__construct();
33
        $this->type = ANSWER_IN_OFFICE_DOC;
34
        $this->isContent = $this->getIsContent();
35
    }
36
37
    /**
38
     * Initialize the file path structure.
39
     */
40
    public function initFile(int $sessionId, int $userId, int $exerciseId, int $exeId): void
41
    {
42
        $this->sessionId = $sessionId ?: 0;
43
        $this->userId = $userId;
44
        $this->exerciseId = $exerciseId ?: 0;
45
        $this->exeId = $exeId;
46
47
        $this->storePath = $this->generateDirectory();
48
        $this->fileName = $this->generateFileName();
49
        $this->filePath = $this->storePath . $this->fileName;
50
    }
51
52
    /**
53
     * Create form for uploading an Office document.
54
     */
55
    public function createAnswersForm($form): void
56
    {
57
        if (!empty($this->exerciseList)) {
58
            $this->exerciseId = reset($this->exerciseList);
59
        }
60
61
        $allowedFormats = [
62
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
63
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',      // .xlsx
64
            'application/msword',                                                     // .doc
65
            'application/vnd.ms-excel'                                                // .xls
66
        ];
67
68
        $form->addElement('file', 'office_file', get_lang('UploadOfficeDoc'));
69
        $form->addRule('office_file', get_lang('ThisFieldIsRequired'), 'required');
70
        $form->addRule('office_file', get_lang('InvalidFileFormat'), 'mimetype', $allowedFormats);
71
72
        $allowedExtensions = implode(', ', ['.docx', '.xlsx', '.doc', '.xls']);
73
        $form->addElement('static', 'file_hint', get_lang('AllowedFormats'), "<p>{$allowedExtensions}</p>");
74
75
        if (!empty($this->extra)) {
76
            $fileUrl = api_get_path(WEB_COURSE_PATH) . $this->getStoredFilePath();
77
            $form->addElement('static', 'current_office_file', get_lang('CurrentOfficeDoc'), "<a href='{$fileUrl}' target='_blank'>{$this->extra}</a>");
78
        }
79
80
        $form->addText('weighting', get_lang('Weighting'), ['class' => 'span1']);
81
82
        global $text;
83
        $form->addButtonSave($text, 'submitQuestion');
84
85
        if (!empty($this->iid)) {
86
            $form->setDefaults(['weighting' => float_format($this->weighting, 1)]);
87
        } else {
88
            if ($this->isContent == 1) {
89
                $form->setDefaults(['weighting' => '10']);
90
            }
91
        }
92
    }
93
94
    /**
95
     * Process the uploaded document and save it.
96
     */
97
    public function processAnswersCreation($form, $exercise): void
98
    {
99
        if (!empty($_FILES['office_file']['name'])) {
100
            $extension = pathinfo($_FILES['office_file']['name'], PATHINFO_EXTENSION);
101
            $tempFilename = "office_" . uniqid() . "." . $extension;
0 ignored issues
show
Bug introduced by
Are you sure $extension of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

101
            $tempFilename = "office_" . uniqid() . "." . /** @scrutinizer ignore-type */ $extension;
Loading history...
102
            $tempPath = sys_get_temp_dir() . '/' . $tempFilename;
103
104
            if (!move_uploaded_file($_FILES['office_file']['tmp_name'], $tempPath)) {
105
                return;
106
            }
107
108
            $this->weighting = $form->getSubmitValue('weighting');
109
            $this->extra = "";
110
            $this->save($exercise);
111
112
            $this->exerciseId = $exercise->iid;
113
            $uploadDir = $this->generateDirectory();
114
115
            if (!is_dir($uploadDir)) {
116
                mkdir($uploadDir, 0775, true);
117
            }
118
119
            $filename = "office_".$this->iid.".".$extension;
120
            $filePath = $uploadDir . $filename;
121
122
            if (!rename($tempPath, $filePath)) {
123
                return;
124
            }
125
126
            $this->extra = $filename;
127
            $this->save($exercise);
128
        }
129
    }
130
131
    /**
132
     * Generate the necessary directory for OnlyOffice documents.
133
     */
134
    private function generateDirectory(): string
135
    {
136
        $exercisePath = api_get_path(SYS_COURSE_PATH).$this->course['path']."/exercises/onlyoffice/{$this->exerciseId}/{$this->iid}/";
137
138
        if (!is_dir($exercisePath)) {
139
            mkdir($exercisePath, 0775, true);
140
        }
141
142
        return rtrim($exercisePath, '/') . '/';
143
    }
144
145
    /**
146
     * Get the stored file path dynamically.
147
     */
148
    public function getStoredFilePath(): ?string
149
    {
150
        if (empty($this->extra)) {
151
            return null;
152
        }
153
154
        return "{$this->course['path']}/exercises/onlyoffice/{$this->exerciseId}/{$this->iid}/{$this->extra}";
155
    }
156
157
    /**
158
     * Get the absolute file path. Returns null if the file doesn't exist.
159
     */
160
    public function getFileUrl(bool $loadFromDatabase = false): ?string
161
    {
162
        if ($loadFromDatabase) {
163
            $em = Database::getManager();
164
            $result = $em->getRepository('ChamiloCoreBundle:TrackEAttempt')->findOneBy([
165
                'exeId' => $this->exeId,
166
                'userId' => $this->userId,
167
                'questionId' => $this->iid,
168
                'sessionId' => $this->sessionId,
169
                'cId' => $this->course['real_id'],
170
            ]);
171
172
            if (!$result || empty($result->getFilename())) {
173
                return null;
174
            }
175
176
            $this->fileName = $result->getFilename();
177
        } else {
178
            if (empty($this->extra)) {
179
                return null;
180
            }
181
182
            $this->fileName = $this->extra;
183
        }
184
185
        $filePath = $this->getStoredFilePath();
186
187
        if (is_file(api_get_path(SYS_COURSE_PATH) . $filePath)) {
188
            return $filePath;
189
        }
190
191
        return null;
192
    }
193
194
    /**
195
     * Show the question in an exercise.
196
     */
197
    public function return_header(Exercise $exercise, $counter = null, $score = [])
198
    {
199
        $score['revised'] = $this->isQuestionWaitingReview($score);
200
        $header = parent::return_header($exercise, $counter, $score);
201
        $header .= '<table class="'.$this->question_table_class.'">
202
            <tr>
203
                <th>'.get_lang("Answer").'</th>
204
            </tr>';
205
206
        return $header;
207
    }
208
209
    /**
210
     * Generate the file name for the OnlyOffice document.
211
     */
212
    private function generateFileName(): string
213
    {
214
        return 'office_' . uniqid();
215
    }
216
}
217