13 namespace Fossology\UI\Api\Controllers;
33 use Psr\Container\ContainerInterface;
34 use Psr\Http\Message\ServerRequestInterface as Request;
35 use Slim\Psr7\Factory\StreamFactory;
84 $this->licenseDao = $this->container->get(
'dao.license');
85 $this->adminLicenseAckDao = $this->container->get(
'dao.license.acknowledgement');
86 $this->licenseStdCommentDao = $this->container->get(
'dao.license.stdc');
100 $shortName = $args[
"shortname"];
102 if (empty($shortName)) {
106 $license = $this->licenseDao->getLicenseByShortName($shortName,
107 $this->restHelper->getGroupId());
109 if ($license ===
null) {
111 "No license found with short name '$shortName'.");
114 $obligations = $this->licenseDao->getLicenseObligations([$license->getId()],
116 $obligations = array_merge($obligations,
117 $this->licenseDao->getLicenseObligations([$license->getId()],
true));
118 $obligationList = [];
119 foreach ($obligations as $obligation) {
121 $obligation[
'ob_pk'],
122 $obligation[
'ob_topic'],
123 $obligation[
'ob_type'],
124 $obligation[
'ob_text'],
125 $obligation[
'ob_classification'],
126 $obligation[
'ob_comment']
132 $license->getShortName(),
133 $license->getFullName(),
140 return $response->withJson($returnVal->getArray(), 200);
154 $query = $request->getQueryParams();
155 $limit = $request->getHeaderLine(self::LIMIT_PARAM);
156 if (! empty($limit)) {
157 $limit = filter_var($limit, FILTER_VALIDATE_INT);
160 "limit should be positive integer > 1");
167 if (array_key_exists(
"kind", $query) && !empty($query[
"kind"]) &&
168 in_array($query[
"kind"], [
"all",
"candidate",
"main"])) {
169 $kind = $query[
"kind"];
172 $totalPages = $this->dbHelper->getLicenseCount($kind,
173 $this->restHelper->getGroupId());
174 $totalPages = intval(ceil($totalPages / $limit));
176 $page = $request->getHeaderLine(self::PAGE_PARAM);
177 if (! empty($page) || $page ==
"0") {
178 $page = filter_var($page, FILTER_VALIDATE_INT);
181 "page should be positive integer > 0");
183 if ($totalPages != 0 && $page > $totalPages) {
185 "Can not exceed total pages: $totalPages"))
186 ->setHeaders([
"X-Total-Pages" => $totalPages]);
191 $onlyActive = $request->getHeaderLine(self::ACTIVE_PARAM);
192 if (! empty($onlyActive)) {
193 $onlyActive = filter_var($onlyActive, FILTER_VALIDATE_BOOLEAN);
198 $licenses = $this->dbHelper->getLicensesPaginated($page, $limit,
199 $kind, $this->restHelper->getGroupId(), $onlyActive);
202 foreach ($licenses as $license) {
205 $license[
'rf_shortname'],
206 $license[
'rf_fullname'],
211 $license[
'group_fk'] != 0
213 $licenseList[] = $newRow->getArray();
216 return $response->withHeader(
"X-Total-Pages", $totalPages)
217 ->withJson($licenseList, 200);
233 if ($newLicense === -1) {
235 "Input contains additional properties.");
237 if ($newLicense === -2) {
242 "non-candidate license.");
244 $tableName =
"license_ref";
246 "rf_shortname" => $newLicense->getShortName(),
247 "rf_fullname" => $newLicense->getFullName(),
248 "rf_text" => $newLicense->getText(),
249 "rf_md5" => md5($newLicense->getText()),
250 "rf_risk" => $newLicense->getRisk(),
251 "rf_url" => $newLicense->getUrl(),
252 "rf_detector_type" => 1
255 if ($newLicense->getIsCandidate()) {
256 $tableName =
"license_candidate";
257 $assocData[
"group_fk"] = $this->restHelper->getGroupId();
258 $assocData[
"rf_user_fk_created"] = $this->restHelper->getUserId();
259 $assocData[
"rf_user_fk_modified"] = $this->restHelper->getUserId();
260 $assocData[
"marydone"] = $newLicense->getMergeRequest();
261 $okToAdd = $this->
isNewLicense($newLicense->getShortName(),
262 $this->restHelper->getGroupId());
264 $okToAdd = $this->
isNewLicense($newLicense->getShortName());
268 $newLicense->getShortName() .
"' already exists!");
271 $rfPk = $this->dbHelper->getDbManager()->insertTableRow($tableName,
272 $assocData, __METHOD__ .
".newLicense",
"rf_pk");
273 $newInfo =
new Info(201, $rfPk, InfoType::INFO);
276 "License with same text already exists!", $e);
278 return $response->withJson($newInfo->getArray(), $newInfo->getCode());
293 $shortName = $args[
"shortname"];
294 if (empty($shortName)) {
298 $license = $this->licenseDao->getLicenseByShortName($shortName,
299 $this->restHelper->getGroupId());
301 if ($license ===
null) {
303 "No license found with short name '$shortName'.");
305 $isCandidate = $this->restHelper->getDbHelper()->doesIdExist(
306 "license_candidate",
"rf_pk", $license->getId());
309 "Need to be admin to edit non-candidate license.");
311 if ($isCandidate && ! $this->restHelper->getUserDao()->isAdvisorOrAdmin(
312 $this->restHelper->getUserId(), $this->restHelper->getGroupId())) {
314 "Operation not permitted for this group.");
318 if (array_key_exists(
'fullName', $newParams)) {
321 if (array_key_exists(
'text', $newParams)) {
324 if (array_key_exists(
'url', $newParams)) {
327 if (array_key_exists(
'risk', $newParams)) {
328 $assocData[
'rf_risk'] = intval($newParams[
'risk']);
330 if (empty($assocData)) {
334 $tableName =
"license_ref";
336 $tableName =
"license_candidate";
338 $this->dbHelper->getDbManager()->updateTableRow($tableName, $assocData,
339 "rf_pk", $license->getId(), __METHOD__ .
".updateLicense");
340 $newInfo =
new Info(200,
"License " . $license->getShortName() .
341 " updated.", InfoType::INFO);
342 return $response->withJson($newInfo->getArray(), $newInfo->getCode());
353 $tableName =
"ONLY license_ref";
355 $params = [$shortName];
356 $statement = __METHOD__;
358 $tableName =
"license_candidate";
359 $where =
"AND group_fk = $2";
360 $params[] = $groupId;
361 $statement .=
".candidate";
363 $sql =
"SELECT count(*) cnt FROM " .
364 "$tableName WHERE rf_shortname = $1 $where;";
365 $result = $this->dbHelper->getDbManager()->getSingleRow($sql, $params,
367 return $result[
"cnt"] == 0;
379 public function handleImportLicense($request, $response, $args)
382 $symReq = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
384 $adminLicenseFromCsv = $this->restHelper->getPlugin(
'admin_license_from_csv');
386 $uploadedFile = $symReq->files->get($adminLicenseFromCsv->getFileInputName(),
392 if (array_key_exists(
"delimiter", $requestBody) && !empty($requestBody[
"delimiter"])) {
393 $delimiter = $requestBody[
"delimiter"];
395 if (array_key_exists(
"enclosure", $requestBody) && !empty($requestBody[
"enclosure"])) {
396 $enclosure = $requestBody[
"enclosure"];
399 $res = $adminLicenseFromCsv->handleFileUpload($uploadedFile, $delimiter,
403 throw new HttpBadRequestException($res[1]);
406 $newInfo =
new Info($res[2], $res[1], InfoType::INFO);
407 return $response->withJson($newInfo->getArray(), $newInfo->getCode());
419 public function getCandidates($request, $response, $args)
423 $adminLicenseCandidate = $this->restHelper->getPlugin(
"admin_license_candidate");
425 return $response->withJson($licenses, 200);
437 public function deleteAdminLicenseCandidate($request, $response, $args)
440 $id = intval($args[
'id']);
442 $adminLicenseCandidate = $this->restHelper->getPlugin(
'admin_license_candidate');
444 if (!$adminLicenseCandidate->getDataRow($id)) {
445 throw new HttpNotFoundException(
"License candidate not found.");
447 $res = $adminLicenseCandidate->doDeleteCandidate($id,
false);
448 $message = $res->getContent();
449 if ($res->getContent() !==
'true') {
450 throw new HttpConflictException(
451 "License used at following locations, can not delete: " .
454 $resInfo =
new Info(202,
"License candidate will be deleted.",
456 return $response->withJson($resInfo->getArray(), $resInfo->getCode());
471 $res = $this->adminLicenseAckDao->getAllAcknowledgements();
473 foreach ($res as $key => $ack) {
474 $res[$key][
'id'] = intval($ack[
'la_pk']);
475 unset($res[$key][
'la_pk']);
476 $res[$key][
'is_enabled'] = $ack[
'is_enabled'] ==
"t";
479 return $response->withJson($res, 200);
500 if (!is_array($body)) {
503 foreach (array_keys($body) as $index) {
504 $ackReq = $body[$index];
505 if ((!$ackReq[
'update'] && empty($ackReq[
'name'])) || ($ackReq[
'update'] && empty($ackReq[
'name']) && !$ackReq[
'toggle'])) {
506 $error =
new Info(400,
"Acknowledgement name missing from the request #" . ($index + 1), InfoType::ERROR);
507 $errors[] = $error->getArray();
509 }
else if ((!$ackReq[
'update'] && empty($ackReq[
'ack'])) || ($ackReq[
'update'] && empty($ackReq[
'ack']) && !$ackReq[
'toggle'])) {
510 $error =
new Info(400,
"Acknowledgement text missing from the request #" . ($index + 1), InfoType::ERROR);
511 $errors[] = $error->getArray();
515 if ($ackReq[
'update']) {
517 if (empty($ackReq[
'id'])) {
518 $error =
new Info(400,
"Acknowledgement ID missing from the request #" . ($index + 1), InfoType::ERROR);
519 $errors[] = $error->getArray();
523 $sql =
"SELECT la_pk, name FROM license_std_acknowledgement WHERE la_pk = $1;";
524 $existingAck = $this->dbHelper->getDbManager()->getSingleRow($sql, [$ackReq[
'id']]);
526 if (empty($existingAck)) {
527 $error =
new Info(404,
"Acknowledgement not found for the request #" . ($index + 1), InfoType::ERROR);
528 $errors[] = $error->getArray();
530 }
else if ($existingAck[
"name"] != $ackReq[
"name"] && $this->dbHelper->doesIdExist(
"license_std_acknowledgement",
"name", $ackReq[
"name"])) {
531 $error =
new Info(400,
"Name already exists.", InfoType::ERROR);
532 $errors[] = $error->getArray();
536 if ($ackReq[
"name"] && $ackReq[
"ack"]) {
537 $this->adminLicenseAckDao->updateAcknowledgement($ackReq[
"id"], $ackReq[
"name"], $ackReq[
"ack"]);
540 if ($ackReq[
"toggle"]) {
541 $this->adminLicenseAckDao->toggleAcknowledgement($ackReq[
"id"]);
544 $info =
new Info(200,
"Successfully updated admin license acknowledgement with name '" . $existingAck[
"name"] .
"'", InfoType::INFO);
547 if ($this->dbHelper->doesIdExist(
"license_std_acknowledgement",
"name", $ackReq[
"name"])) {
548 $error =
new Info(400,
"Name already exists for the request #" . ($index + 1), InfoType::ERROR);
549 $errors[] = $error->getArray();
552 $res = $this->adminLicenseAckDao->insertAcknowledgement($ackReq[
"name"], $ackReq[
"ack"]);
554 $error =
new Info(500,
"Error while inserting new acknowledgement.", InfoType::ERROR);
555 $errors[] = $error->getArray();
558 $info =
new Info(201,
"Acknowledgement added successfully.", InfoType::INFO);
560 $success[] = $info->getArray();
562 return $response->withJson([
563 'success' => $success,
578 $res = $this->licenseStdCommentDao->getAllComments();
579 foreach ($res as $key => $ack) {
580 $res[$key][
'id'] = intval($ack[
'lsc_pk']);
581 $res[$key][
'is_enabled'] = $ack[
'is_enabled'] ==
"t";
582 unset($res[$key][
'lsc_pk']);
584 return $response->withJson($res, 200);
607 if (!is_array($body)) {
610 foreach (array_keys($body) as $index) {
611 $commentReq = $body[$index];
614 if ((!$commentReq[
'update'] && empty($commentReq[
'name']))) {
615 $error =
new Info(400,
"Comment name missing from the request #" . ($index + 1), InfoType::ERROR);
616 $errors[] = $error->getArray();
618 }
else if ((!$commentReq[
'update'] && empty($commentReq[
'comment']))) {
619 $error =
new Info(400,
"Comment text missing from the request #" . ($index + 1), InfoType::ERROR);
620 $errors[] = $error->getArray();
622 }
else if ($commentReq[
'update'] && empty($commentReq[
'name']) && empty($commentReq[
'comment']) && empty($commentReq[
'toggle'])) {
623 $error =
new Info(400,
"Comment name, text or toggle missing from the request #" . ($index + 1), InfoType::ERROR);
624 $errors[] = $error->getArray();
628 if ($commentReq[
'update']) {
630 if (empty($commentReq[
'id'])) {
631 $error =
new Info(400,
"Standard Comment ID missing from the request #" . ($index + 1), InfoType::ERROR);
632 $errors[] = $error->getArray();
636 $sql =
"SELECT lsc_pk, name, comment FROM license_std_comment WHERE lsc_pk = $1;";
637 $existingComment = $this->dbHelper->getDbManager()->getSingleRow($sql, [$commentReq[
'id']]);
639 if (empty($existingComment)) {
640 $error =
new Info(404,
"Standard comment not found for the request #" . ($index + 1), InfoType::ERROR);
641 $errors[] = $error->getArray();
644 }
else if ($existingComment[
"name"] != $commentReq[
"name"] && $this->dbHelper->doesIdExist(
"license_std_comment",
"name", $commentReq[
"name"])) {
645 $error =
new Info(400,
"Name already exists.", InfoType::ERROR);
646 $errors[] = $error->getArray();
651 if ($commentReq[
"name"] && $commentReq[
"comment"]) {
652 $this->licenseStdCommentDao->updateComment($commentReq[
"id"], $commentReq[
"name"], $commentReq[
"comment"]);
653 }
else if ($commentReq[
"name"]) {
654 $this->licenseStdCommentDao->updateComment($commentReq[
"id"], $commentReq[
"name"], $existingComment[
"comment"]);
655 }
else if ($commentReq[
"comment"]) {
656 $this->licenseStdCommentDao->updateComment($commentReq[
"id"], $existingComment[
"name"], $commentReq[
"comment"]);
659 if ($commentReq[
"toggle"]) {
660 $this->licenseStdCommentDao->toggleComment($commentReq[
"id"]);
663 $info =
new Info(200,
"Successfully updated standard comment", InfoType::INFO);
666 if ($this->dbHelper->doesIdExist(
"license_std_comment",
"name", $commentReq[
"name"])) {
667 $error =
new Info(400,
"Name already exists for the request #" . ($index + 1), InfoType::ERROR);
668 $errors[] = $error->getArray();
671 $res = $this->licenseStdCommentDao->insertComment($commentReq[
"name"], $commentReq[
"comment"]);
673 $error =
new Info(500,
"Error while inserting new comment.", InfoType::ERROR);
674 $errors[] = $error->getArray();
677 $info =
new Info(201,
"Comment with name '". $commentReq[
'name'] .
"' added successfully.", InfoType::INFO);
679 $success[] = $info->getArray();
681 return $response->withJson([
682 'success' => $success,
696 public function verifyLicense($request, $response, $args)
699 $licenseShortName = $args[
"shortname"];
701 $parentName = $body[
"parentShortname"];
703 if (empty($licenseShortName) || empty($parentName)) {
705 "License ShortName or Parent ShortName is missing.");
708 $license = $this->licenseDao->getLicenseByShortName($licenseShortName, $this->restHelper->getGroupId());
709 if ($licenseShortName != $parentName) {
710 $parentLicense = $this->licenseDao->getLicenseByShortName($parentName, $this->restHelper->getGroupId());
712 $parentLicense = $license;
715 if (empty($license) || empty($parentLicense)) {
716 throw new HttpNotFoundException(
"License not found.");
721 $adminLicenseCandidate = $this->restHelper->getPlugin(
'admin_license_candidate');
722 $ok = $adminLicenseCandidate->verifyCandidate($license->getId(), $licenseShortName, $parentLicense->getId());
723 }
catch (\Throwable $th) {
724 throw new HttpConflictException(
'The license text already exists.', $th);
728 throw new HttpBadRequestException(
'Short name must be unique');
730 $with = $parentLicense->getId() === $license->getId() ?
'' :
" as variant of ($parentName).";
731 $info =
new Info(200,
'Successfully verified candidate ('.$licenseShortName.
')'.$with, InfoType::INFO);
732 return $response->withJson($info->getArray(), $info->getCode());
744 public function mergeLicense($request, $response, $args)
747 $licenseShortName = $args[
"shortname"];
749 $parentName = $body[
"parentShortname"];
751 if (empty($licenseShortName) || empty($parentName)) {
752 throw new HttpBadRequestException(
753 "License ShortName or Parent ShortName is missing.");
755 if ($licenseShortName == $parentName) {
756 throw new HttpBadRequestException(
757 "License ShortName and Parent ShortName are same.");
760 $license = $this->licenseDao->getLicenseByShortName($licenseShortName, $this->restHelper->getGroupId());
761 $mergeLicense = $this->licenseDao->getLicenseByShortName($parentName, $this->restHelper->getGroupId());
763 if (empty($license) || empty($mergeLicense)) {
764 throw new HttpNotFoundException(
"License not found.");
768 $adminLicenseCandidate = $this->restHelper->getPlugin(
'admin_license_candidate');
769 $vars = $adminLicenseCandidate->getDataRow($license->getId());
771 throw new HttpNotFoundException(
"Candidate license not found.");
775 $vars[
'shortname'] = $vars[
'rf_shortname'];
776 $ok = $adminLicenseCandidate->mergeCandidate($license->getId(), $mergeLicense->getId(), $vars);
777 }
catch (\Throwable $th) {
778 throw new HttpConflictException(
'The license text already exists.', $th);
782 throw new HttpInternalServerErrorException(
"Please try again later.");
784 $info =
new Info(200,
"Successfully merged candidate ($parentName) into ($licenseShortName).", InfoType::INFO);
785 return $response->withJson($info->getArray(), $info->getCode());
797 public function getSuggestedLicense($request, $response, $args)
801 $rfText = $body[
"referenceText"];
802 if (empty($rfText)) {
803 throw new HttpBadRequestException(
"Reference text is missing.");
806 $adminLicenseCandidate = $this->restHelper->getPlugin(
'admin_license_candidate');
807 list ($suggestIds, $rendered) = $adminLicenseCandidate->suggestLicenseId($rfText,
true);
810 foreach ($rendered as $value) {
811 $highlights[] = $value->getArray();
814 if (! empty($suggestIds)) {
815 $suggest = $suggestIds[0];
816 $suggestLicense = $adminLicenseCandidate->getDataRow($suggest,
'ONLY license_ref');
818 'id' => intval($suggestLicense[
'rf_pk']),
819 'spdxName' => $suggestLicense[
'rf_spdx_id'],
820 'shortName' => $suggestLicense[
'rf_shortname'],
821 'fullName' => $suggestLicense[
'rf_fullname'],
822 'text' => $suggestLicense[
'rf_text'],
823 'url' => $suggestLicense[
'rf_url'],
824 'notes' => $suggestLicense[
'rf_notes'],
825 'risk' => intval($suggestLicense[
'rf_risk']),
826 'highlights' => $highlights,
829 if (empty($suggestLicense)) {
830 $suggestLicense = [];
832 return $response->withJson($suggestLicense, 200);
847 $query = $request->getQueryParams();
849 if (array_key_exists(
'id', $query)) {
850 $rf = intval($query[
'id']);
853 (! $this->dbHelper->doesIdExist(
"license_ref",
"rf_pk", $rf) &&
854 ! $this->dbHelper->doesIdExist(
"license_candidate",
"rf_pk", $rf))) {
857 $dbManager = $this->dbHelper->getDbManager();
859 $content = $licenseCsvExport->createCsv($rf);
860 $fileName =
"fossology-license-export-" . date(
"YMj-Gis");
861 $newResponse = $response->withHeader(
'Content-type',
'text/csv, charset=UTF-8')
862 ->withHeader(
'Content-Disposition',
'attachment; filename=' . $fileName .
'.csv')
863 ->withHeader(
'Pragma',
'no-cache')
864 ->withHeader(
'Cache-Control',
'no-cache, must-revalidate, maxage=1, post-check=0, pre-check=0')
865 ->withHeader(
'Expires',
'Expires: Thu, 19 Nov 1981 08:52:00 GMT');
866 $sf =
new StreamFactory();
867 return $newResponse->withBody(
868 $content ? $sf->createStream($content) : $sf->createStream(
'')
Helper class to export license list as a CSV from the DB.
Contains the constants and helpers for authentication of user.
static isAdmin()
Check if user is admin.
static replaceUnicodeControlChar($input, $replace="")
handleLicenseStandardComment($request, $response, $args)
handleAdminLicenseAcknowledgement($request, $response, $args)
isNewLicense($shortName, $groupId=0)
createLicense($request, $response, $args)
updateLicense($request, $response, $args)
exportAdminLicenseToCSV($request, $response, $args)
getAllLicenseStandardComments($request, $response, $args)
const LICENSE_FETCH_LIMIT
getAllAdminAcknowledgements($request, $response, $args)
getAllLicenses($request, $response, $args)
getLicense($request, $response, $args)
Base controller for REST calls.
getParsedBody(ServerRequestInterface $request)
Parse request body as JSON and return associative PHP array.
Override Slim response for withJson function.
Different type of infos provided by REST.
Info model to contain general error and return values.
static convertDbArray($rows)
static parseFromArray($inputLicense)