Issues (2128)

main/exercise/AnswerInOfficeDoc.php (1 issue)

Labels
Severity
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
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
     * Get the stored file path dynamically.
133
     */
134
    public function getStoredFilePath(): ?string
135
    {
136
        if (empty($this->extra)) {
137
            return null;
138
        }
139
140
        return "{$this->course['path']}/exercises/onlyoffice/{$this->exerciseId}/{$this->iid}/{$this->extra}";
141
    }
142
143
    /**
144
     * Get the absolute file path. Returns null if the file doesn't exist.
145
     */
146
    public function getFileUrl(bool $loadFromDatabase = false): ?string
147
    {
148
        if ($loadFromDatabase) {
149
            $em = Database::getManager();
150
            $result = $em->getRepository('ChamiloCoreBundle:TrackEAttempt')->findOneBy([
151
                'exeId' => $this->exeId,
152
                'userId' => $this->userId,
153
                'questionId' => $this->iid,
154
                'sessionId' => $this->sessionId,
155
                'cId' => $this->course['real_id'],
156
            ]);
157
158
            if (!$result || empty($result->getFilename())) {
159
                return null;
160
            }
161
162
            $this->fileName = $result->getFilename();
163
        } else {
164
            if (empty($this->extra)) {
165
                return null;
166
            }
167
168
            $this->fileName = $this->extra;
169
        }
170
171
        $filePath = $this->getStoredFilePath();
172
173
        if (is_file(api_get_path(SYS_COURSE_PATH).$filePath)) {
174
            return $filePath;
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * Show the question in an exercise.
182
     */
183
    public function return_header(Exercise $exercise, $counter = null, $score = [])
184
    {
185
        $score['revised'] = $this->isQuestionWaitingReview($score);
186
        $header = parent::return_header($exercise, $counter, $score);
187
        $header .= '<table class="'.$this->question_table_class.'">
188
            <tr>
189
                <th>'.get_lang("Answer").'</th>
190
            </tr>';
191
192
        return $header;
193
    }
194
195
    /**
196
     * Generate the necessary directory for OnlyOffice documents.
197
     */
198
    private function generateDirectory(): string
199
    {
200
        $exercisePath = api_get_path(SYS_COURSE_PATH).$this->course['path']."/exercises/onlyoffice/{$this->exerciseId}/{$this->iid}/";
201
202
        if (!is_dir($exercisePath)) {
203
            mkdir($exercisePath, 0775, true);
204
        }
205
206
        return rtrim($exercisePath, '/').'/';
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