diff --git a/README.md b/README.md index ece6c6d2..23654ad8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Backend && Frontend for FreeHackQuest on Qt and WebSockets | -------------- | ------------- | | fhq-server | [ubuntu/ppa](https://launchpad.net/~freehackquest/+archive/ubuntu/fhq-server) | | fhq-server | [![Docker Pulls](https://img.shields.io/docker/pulls/freehackquest/fhq-server.svg)](https://hub.docker.com/r/freehackquest/fhq-server/) | -| client library | [![npm version](https://badge.fury.io/js/libfhqcli-web-js.svg)](https://badge.fury.io/js/libfhqcli-web-js) | +| client library | [![npm version](https://badge.fury.io/js/freehackquest-libclient-js.svg)](https://badge.fury.io/js/freehackquest-libclient-web-js) | | client library | [![PyPI version](https://badge.fury.io/py/libfreehackquestclient.svg)](https://badge.fury.io/py/libfreehackquestclient) | | frontend | [github/web](https://github.com/freehackquest/frontend) | diff --git a/fhq-server/CMakeLists.txt b/fhq-server/CMakeLists.txt index 7ff4c38b..a10d6fa3 100644 --- a/fhq-server/CMakeLists.txt +++ b/fhq-server/CMakeLists.txt @@ -201,6 +201,8 @@ list (APPEND WSJCPP_SOURCES "src/storages/updates/update_snwxenqco0_csww6lwcrp.h list (APPEND WSJCPP_SOURCES "src/storages/updates/update_snwxenqco0_csww6lwcrp.cpp") list (APPEND WSJCPP_SOURCES "src/storages/updates/update_csww6lwcrp_722kt134lq.h") list (APPEND WSJCPP_SOURCES "src/storages/updates/update_csww6lwcrp_722kt134lq.cpp") +list (APPEND WSJCPP_SOURCES "src/storages/updates/update_722kt134lq_6c8d4zm6u2.h") +list (APPEND WSJCPP_SOURCES "src/storages/updates/update_722kt134lq_6c8d4zm6u2.cpp") list (APPEND WSJCPP_SOURCES "src/storages/updates/update0101.h") list (APPEND WSJCPP_SOURCES "src/storages/updates/update0101.cpp") diff --git a/fhq-server/src.wsjcpp/CMakeLists.txt b/fhq-server/src.wsjcpp/CMakeLists.txt index ae1977b4..f1867971 100644 --- a/fhq-server/src.wsjcpp/CMakeLists.txt +++ b/fhq-server/src.wsjcpp/CMakeLists.txt @@ -1,7 +1,7 @@ # Automaticly generated by wsjcpp@v0.1.5 cmake_minimum_required(VERSION 3.0) -add_definitions(-DWSJCPP_APP_VERSION="v0.2.29") +add_definitions(-DWSJCPP_APP_VERSION="v0.2.30") add_definitions(-DWSJCPP_APP_NAME="fhq-server") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/fhq-server/src/cmd/cmd_handlers_useful_links.cpp b/fhq-server/src/cmd/cmd_handlers_useful_links.cpp index 8ffc3398..a00b9cec 100644 --- a/fhq-server/src/cmd/cmd_handlers_useful_links.cpp +++ b/fhq-server/src/cmd/cmd_handlers_useful_links.cpp @@ -21,6 +21,7 @@ CmdHandlerUsefulLinksList::CmdHandlerUsefulLinksList() setAccessAdmin(true); optionalStringParam("filter", "Filter by word"); + optionalStringParam("filter_by_tag", "Filter by tag"); optionalIntegerParam("page_index", "Page Index"); optionalIntegerParam("page_size", "Page Size (default 10)"); @@ -51,6 +52,19 @@ struct QueryFilters { sWhere += ")"; vCompiledWhere.push_back(sWhere); }; + + void equal(std::string sField, std::string sValue) { + std::string sWhere = "("; + QueryFilter f; + f.sColumnName = sField; + f.sFilterName = ":" + sField; + f.sValue = sValue; + vFilters.push_back(f); + sWhere += f.sColumnName + " = " + f.sFilterName; + sWhere += ")"; + vCompiledWhere.push_back(sWhere); + }; + std::string compileWhere() { if (vCompiledWhere.size() == 0) { return ""; @@ -87,6 +101,7 @@ void CmdHandlerUsefulLinksList::handle(ModelRequest *pRequest) { bool bIsAdmin = pRequest->isAdmin(); std::string sFilter = pRequest->getInputString("filter", ""); + std::string sFilterByTag = pRequest->getInputString("filter_by_tag", ""); int nPageIndex = pRequest->getInputInteger("page_index", 0); int nPageSize = pRequest->getInputInteger("page_size", 10); int nLength = 0; @@ -96,6 +111,12 @@ void CmdHandlerUsefulLinksList::handle(ModelRequest *pRequest) { if (sFilter != "") { queryFilters.like({"url", "description"}, sFilter); } + + std::string sInnerJoinTags = ""; + if (sFilterByTag != "") { + sInnerJoinTags = " INNER JOIN useful_links_tags t2 ON t0.id = t2.usefullinkid "; + queryFilters.equal("tagvalue", sFilterByTag); + } QString sWhere = ""; EmployDatabase *pDatabase = findWsjcppEmploy(); @@ -105,6 +126,7 @@ void CmdHandlerUsefulLinksList::handle(ModelRequest *pRequest) { // count query.prepare("SELECT COUNT(*) AS cnt FROM useful_links t0 " " LEFT JOIN useful_links_user_favorites t1 ON t1.usefullinkid = t0.id AND t1.userid = :userid " + + QString::fromStdString(sInnerJoinTags) + QString::fromStdString(queryFilters.compileWhere()) ); query.bindValue(":userid", nUserId); @@ -125,6 +147,7 @@ void CmdHandlerUsefulLinksList::handle(ModelRequest *pRequest) { query.prepare("SELECT t0.*, t1.userid FROM useful_links t0 " " LEFT JOIN useful_links_user_favorites t1 ON t1.usefullinkid = t0.id AND t1.userid = :userid " + + QString::fromStdString(sInnerJoinTags) + QString::fromStdString(queryFilters.compileWhere()) + " ORDER BY user_favorites DESC, user_clicks DESC, dt DESC " " LIMIT " + QString::number(nPageIndex*nPageSize) + "," + QString::number(nPageSize) @@ -153,6 +176,8 @@ void CmdHandlerUsefulLinksList::handle(ModelRequest *pRequest) { } else { jsonLink["favorite"] = false; } + std::string sTags = record.value("tags").toString().toStdString(); + jsonLink["tags"] = WsjcppCore::split(sTags, ","); jsonItems.push_back(jsonLink); } jsonData["items"] = jsonItems; @@ -173,7 +198,7 @@ CmdHandlerUsefulLinksRetrieve::CmdHandlerUsefulLinksRetrieve() setActivatedFromVersion("0.2.28"); - setAccessUnauthorized(false); + setAccessUnauthorized(true); setAccessUser(true); setAccessAdmin(true); @@ -224,6 +249,23 @@ void CmdHandlerUsefulLinksRetrieve::handle(ModelRequest *pRequest) { } } + // tags + query.prepare("SELECT * FROM useful_links_tags WHERE usefullinkid = :useful_link_id"); + query.bindValue(":useful_link_id", nUsefulLinkId); + + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + nlohmann::json jsonLinkTags = nlohmann::json::array(); + while (query.next()) { + QSqlRecord record = query.record(); + std::string sTag = record.value("tagvalue").toString().toHtmlEscaped().toStdString(); + jsonLinkTags.push_back(sTag); + } + jsonLink["tags"] = jsonLinkTags; + nlohmann::json jsonResponse; jsonResponse["data"] = jsonLink; pRequest->sendMessageSuccess(cmd(), jsonResponse); @@ -264,10 +306,11 @@ void CmdHandlerUsefulLinksAdd::handle(ModelRequest *pRequest) { QSqlDatabase db = *(pDatabase->database()); QSqlQuery query(db); // TODO uuid - query.prepare("INSERT INTO useful_links(url,description,author,stars,dt) VALUES(:url, :description, :author, 0, NOW())"); + query.prepare("INSERT INTO useful_links(url,description,author,tags,dt) VALUES(:url, :description, :author, :tags, NOW())"); query.bindValue(":url", QString::fromStdString(sUrl)); query.bindValue(":description", QString::fromStdString(sDescription)); query.bindValue(":author", QString::fromStdString(sAuthor)); + query.bindValue(":tags", QString::fromStdString("")); if (!query.exec()) { pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); @@ -336,6 +379,14 @@ void CmdHandlerUsefulLinksDelete::handle(ModelRequest *pRequest) { return; } + query.prepare("DELETE FROM useful_links_tags WHERE usefullinkid = :useful_link_id"); + query.bindValue(":useful_link_id", nUsefulLinkId); + + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + nlohmann::json jsonResponse; pRequest->sendMessageSuccess(cmd(), jsonResponse); } @@ -669,6 +720,8 @@ void CmdHandlerUsefulLinksCommentList::handle(ModelRequest *pRequest) { // --------------------------------------------------------------------- // Useful Links add comment +REGISTRY_CMD(CmdHandlerUsefulLinksCommentAdd) + CmdHandlerUsefulLinksCommentAdd::CmdHandlerUsefulLinksCommentAdd() : CmdHandlerBase("useful_links_comment_add", "Useful Links add comment") { @@ -692,6 +745,8 @@ void CmdHandlerUsefulLinksCommentAdd::handle(ModelRequest *pRequest) { // --------------------------------------------------------------------- // Useful Links remove comment +REGISTRY_CMD(CmdHandlerUsefulLinksCommentDelete) + CmdHandlerUsefulLinksCommentDelete::CmdHandlerUsefulLinksCommentDelete() : CmdHandlerBase("useful_links_comment_delete", "Useful Links remove comment") { @@ -715,6 +770,8 @@ void CmdHandlerUsefulLinksCommentDelete::handle(ModelRequest *pRequest) { // --------------------------------------------------------------------- // Useful Links List of tags +REGISTRY_CMD(CmdHandlerUsefulLinksTagList) + CmdHandlerUsefulLinksTagList::CmdHandlerUsefulLinksTagList() : CmdHandlerBase("useful_links_tag_list", "Useful Links - List of tags") { @@ -729,12 +786,38 @@ CmdHandlerUsefulLinksTagList::CmdHandlerUsefulLinksTagList() // --------------------------------------------------------------------- void CmdHandlerUsefulLinksTagList::handle(ModelRequest *pRequest) { - pRequest->sendMessageError(cmd(), WsjcppError(501, "Not Implemented Yet")); + + EmployDatabase *pDatabase = findWsjcppEmploy(); + + QSqlDatabase db = *(pDatabase->database()); + QSqlQuery query(db); + + // TODO get from employ + query.prepare("SELECT tagvalue, COUNT(*) AS cnt FROM `useful_links_tags` GROUP BY tagvalue"); + + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + nlohmann::json jsonData = nlohmann::json::array(); + while (query.next()) { + QSqlRecord record = query.record(); + nlohmann::json jsonTagInfo; + jsonTagInfo["tag"] = record.value("tagvalue").toString().toHtmlEscaped().toStdString(); + jsonTagInfo["counter"] = record.value("cnt").toInt(); + jsonData.push_back(jsonTagInfo); + } + nlohmann::json jsonResponse; + jsonResponse["data"] = jsonData; + pRequest->sendMessageSuccess(cmd(), jsonResponse); } // --------------------------------------------------------------------- // Useful Links add tag +REGISTRY_CMD(CmdHandlerUsefulLinksTagAdd) + CmdHandlerUsefulLinksTagAdd::CmdHandlerUsefulLinksTagAdd() : CmdHandlerBase("useful_links_tag_add", "Useful Links add tag") { @@ -745,18 +828,80 @@ CmdHandlerUsefulLinksTagAdd::CmdHandlerUsefulLinksTagAdd() setAccessAdmin(true); requireIntegerParam("useful_link_id", "Id of useful link"); - requireStringParam("tagname", "tag name"); + requireStringParam("tag", "Tag Value"); } // --------------------------------------------------------------------- void CmdHandlerUsefulLinksTagAdd::handle(ModelRequest *pRequest) { - pRequest->sendMessageError(cmd(), WsjcppError(501, "Not Implemented Yet")); + int nUsefulLinkId = pRequest->getInputInteger("useful_link_id", 0); + std::string sTagValue = pRequest->getInputString("tag", ""); + sTagValue = WsjcppCore::trim(sTagValue); + if (sTagValue == "") { + pRequest->sendMessageError(cmd(), WsjcppError(400, "tag could not be empty")); + return; + } + + EmployDatabase *pDatabase = findWsjcppEmploy(); + + QSqlDatabase db = *(pDatabase->database()); + QSqlQuery query(db); + + // TODO get from employ + query.prepare("SELECT * FROM useful_links_tags WHERE usefullinkid = :useful_link_id AND tagvalue = :tagvalue"); + query.bindValue(":useful_link_id", nUsefulLinkId); + query.bindValue(":tagvalue", QString::fromStdString(sTagValue)); + + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + if (query.next()) { + pRequest->sendMessageError(cmd(), WsjcppError(400, "TAG_ALREADY_EXISTS")); + return; + } else { + query.prepare("INSERT INTO useful_links_tags(usefullinkid, tagvalue) VALUES(:useful_link_id, :tagvalue)"); + query.bindValue(":useful_link_id", nUsefulLinkId); + query.bindValue(":tagvalue", QString::fromStdString(sTagValue)); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + // update field useful_links.tags + query.prepare("SELECT * FROM useful_links_tags WHERE usefullinkid = :useful_link_id"); + query.bindValue(":useful_link_id", nUsefulLinkId); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + std::string sTags = ""; + while (query.next()) { + QSqlRecord record = query.record(); + std::string sTag = record.value("tagvalue").toString().toHtmlEscaped().toStdString(); + sTags += sTags.length() == 0 ? "": ","; + sTags += sTag; + } + + query.prepare("UPDATE useful_links SET tags = :tags WHERE id = :useful_link_id"); + query.bindValue(":tags", QString::fromStdString(sTags)); + query.bindValue(":useful_link_id", nUsefulLinkId); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + } + nlohmann::json jsonResponse; + pRequest->sendMessageSuccess(cmd(), jsonResponse); } // --------------------------------------------------------------------- // Useful Links remove tag +REGISTRY_CMD(CmdHandlerUsefulLinksTagDelete) + CmdHandlerUsefulLinksTagDelete::CmdHandlerUsefulLinksTagDelete() : CmdHandlerBase("useful_links_tag_delete", "Useful Links remove tag") { @@ -765,19 +910,79 @@ CmdHandlerUsefulLinksTagDelete::CmdHandlerUsefulLinksTagDelete() setAccessUnauthorized(false); setAccessUser(false); setAccessAdmin(true); - - requireIntegerParam("useful_link_tag_id", "Tag Id for useful link"); + + requireIntegerParam("useful_link_id", "Useful Link Id"); + requireStringParam("tag", "Tag Value"); } // --------------------------------------------------------------------- void CmdHandlerUsefulLinksTagDelete::handle(ModelRequest *pRequest) { - pRequest->sendMessageError(cmd(), WsjcppError(501, "Not Implemented Yet")); + int nUsefulLinkId = pRequest->getInputInteger("useful_link_id", 0); + std::string sTagValue = pRequest->getInputString("tag", ""); + sTagValue = WsjcppCore::trim(sTagValue); + if (sTagValue == "") { + pRequest->sendMessageError(cmd(), WsjcppError(400, "tag could not be empty")); + return; + } + + EmployDatabase *pDatabase = findWsjcppEmploy(); + + QSqlDatabase db = *(pDatabase->database()); + QSqlQuery query(db); + + // TODO get from employ + query.prepare("SELECT * FROM useful_links_tags WHERE usefullinkid = :useful_link_id AND tagvalue = :tagvalue"); + query.bindValue(":useful_link_id", nUsefulLinkId); + query.bindValue(":tagvalue", QString::fromStdString(sTagValue)); + + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + if (query.next()) { + query.prepare("DELETE FROM useful_links_tags WHERE usefullinkid = :useful_link_id AND tagvalue = :tagvalue"); + query.bindValue(":useful_link_id", nUsefulLinkId); + query.bindValue(":tagvalue", QString::fromStdString(sTagValue)); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + // update field useful_links.tags + query.prepare("SELECT * FROM useful_links_tags WHERE usefullinkid = :useful_link_id"); + query.bindValue(":useful_link_id", nUsefulLinkId); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + + std::string sTags = ""; + while (query.next()) { + QSqlRecord record = query.record(); + std::string sTag = record.value("tagvalue").toString().toHtmlEscaped().toStdString(); + sTags += sTags.length() == 0 ? "": ","; + sTags += sTag; + } + + query.prepare("UPDATE useful_links SET tags = :tags WHERE id = :useful_link_id"); + query.bindValue(":tags", QString::fromStdString(sTags)); + query.bindValue(":useful_link_id", nUsefulLinkId); + if (!query.exec()) { + pRequest->sendMessageError(cmd(), WsjcppError(500, query.lastError().text().toStdString())); + return; + } + } + nlohmann::json jsonResponse; + pRequest->sendMessageSuccess(cmd(), jsonResponse); } // --------------------------------------------------------------------- // Useful Links propose link by user +REGISTRY_CMD(CmdHandlerUsefulLinksUserPropose) + CmdHandlerUsefulLinksUserPropose::CmdHandlerUsefulLinksUserPropose() : CmdHandlerBase("useful_links_user_propose", "Useful Links propose link by user") { @@ -801,6 +1006,8 @@ void CmdHandlerUsefulLinksUserPropose::handle(ModelRequest *pRequest) { // --------------------------------------------------------------------- // Useful Links propose link by user +REGISTRY_CMD(CmdHandlerUsefulLinksUserProposeApprove) + CmdHandlerUsefulLinksUserProposeApprove::CmdHandlerUsefulLinksUserProposeApprove() : CmdHandlerBase("useful_links_user_propose_approve", "Useful Links Approve propose link by admin") { diff --git a/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.cpp b/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.cpp new file mode 100644 index 00000000..4f5d4830 --- /dev/null +++ b/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.cpp @@ -0,0 +1,18 @@ +#include "update_722kt134lq_6c8d4zm6u2.h" + +REGISTRY_WSJCPP_STORAGE_UPDATE(Update_722kt134lq_6c8d4zm6u2) + +Update_722kt134lq_6c8d4zm6u2::Update_722kt134lq_6c8d4zm6u2() + : WsjcppStorageUpdateBase("722kt134lq", "6c8d4zm6u2", "TODO") { + + WsjcppStorageModifyTable *useful_links_tags = modifyTable("useful_links_tags"); + useful_links_tags->dropColumn("tags"); + useful_links_tags->dropColumn("counter"); + + WsjcppStorageModifyTable *useful_links = modifyTable("useful_links"); + useful_links->addColumn("tags").string(1024).notNull().defaultValue(""); + useful_links->dropColumn("stars"); + + // fill the array with struct changes +} + diff --git a/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.h b/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.h new file mode 100644 index 00000000..b0375a1d --- /dev/null +++ b/fhq-server/src/storages/updates/update_722kt134lq_6c8d4zm6u2.h @@ -0,0 +1,11 @@ +#ifndef UPDATE_722KT134LQ_6C8D4ZM6U2_H +#define UPDATE_722KT134LQ_6C8D4ZM6U2_H + +#include + +class Update_722kt134lq_6c8d4zm6u2 : public WsjcppStorageUpdateBase { + public: + Update_722kt134lq_6c8d4zm6u2(); +}; + +#endif // UPDATE_722KT134LQ_6C8D4ZM6U2_H diff --git a/fhq-server/unit-tests.wsjcpp/CMakeLists.txt b/fhq-server/unit-tests.wsjcpp/CMakeLists.txt index 9a4c8e65..1f258a8e 100644 --- a/fhq-server/unit-tests.wsjcpp/CMakeLists.txt +++ b/fhq-server/unit-tests.wsjcpp/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) project(unit-tests C CXX) -add_definitions(-DWSJCPP_APP_VERSION="ut-v0.2.29") +add_definitions(-DWSJCPP_APP_VERSION="ut-v0.2.30") add_definitions(-DWSJCPP_APP_NAME="unit-tests-fhq-server") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -95,7 +95,7 @@ list (APPEND WSJCPP_INCLUDE_DIRS "../src.wsjcpp/wsjcpp_parse_conf/") list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_parse_conf/wsjcpp_parse_conf.cpp") list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_parse_conf/wsjcpp_parse_conf.h") -# fhq-server:v0.2.29 +# fhq-server:v0.2.30 list (APPEND WSJCPP_INCLUDE_DIRS "../src") list (APPEND WSJCPP_SOURCES "../src/core/fallen.cpp") list (APPEND WSJCPP_SOURCES "../src/core/fallen.h") diff --git a/fhq-server/wsjcpp.yml b/fhq-server/wsjcpp.yml index 46d7a0d7..316080fc 100644 --- a/fhq-server/wsjcpp.yml +++ b/fhq-server/wsjcpp.yml @@ -3,7 +3,7 @@ cmake_minimum_required: 3.0 cmake_cxx_standard: 11 name: "fhq-server" -version: "v0.2.29" +version: "v0.2.30" description: "This is an open source platform for competitions of computer security." issues: "https://github.com/freehackquest/fhq-server/issues" diff --git a/fhq-web-user/angular.json b/fhq-web-user/angular.json index 4e9a0b3a..c1c78ac7 100644 --- a/fhq-web-user/angular.json +++ b/fhq-web-user/angular.json @@ -31,7 +31,7 @@ "node_modules/highlight.js/styles/dark.css" ], "scripts": [ - "node_modules/libfhqcli-web-js/dist/libfhqcli-web-js.js", + "node_modules/freehackquest-libclient-web-js/dist/freehackquest-libclient-web-js.js", "node_modules/jquery/dist/jquery.slim.min.js", "node_modules/popper.js/dist/umd/popper.min.js", "node_modules/bootstrap/dist/js/bootstrap.bundle.js", diff --git a/fhq-web-user/package-lock.json b/fhq-web-user/package-lock.json index 48051e98..b625bd1a 100644 --- a/fhq-web-user/package-lock.json +++ b/fhq-web-user/package-lock.json @@ -1,6 +1,6 @@ { "name": "fhq-web-user", - "version": "0.2.29", + "version": "0.2.30", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4049,6 +4049,11 @@ "map-cache": "^0.2.2" } }, + "freehackquest-libclient-web-js": { + "version": "0.2.30", + "resolved": "https://registry.npmjs.org/freehackquest-libclient-web-js/-/freehackquest-libclient-web-js-0.2.30.tgz", + "integrity": "sha512-5XaY7eByxnuhFWgnLlaqomoVAliKnih0bJ47fEx4q18sXSEmeL4GuOnbpAv1VrVXJyl5dUkPHTxYNTrQAT0/Mw==" + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -6255,11 +6260,6 @@ } } }, - "libfhqcli-web-js": { - "version": "0.2.29", - "resolved": "https://registry.npmjs.org/libfhqcli-web-js/-/libfhqcli-web-js-0.2.29.tgz", - "integrity": "sha512-VO26NbmVgvAqD4MUkbEJ/JgMd4ftaV3WImKLy0fX9VdPezB4/xEOX1ha3b1U/QNOuynz8Q60RG6BpCLX8hOtgQ==" - }, "license-webpack-plugin": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.1.tgz", diff --git a/fhq-web-user/package.json b/fhq-web-user/package.json index 2379678e..015797cc 100644 --- a/fhq-web-user/package.json +++ b/fhq-web-user/package.json @@ -1,6 +1,6 @@ { "name": "fhq-web-user", - "version": "0.2.29", + "version": "0.2.30", "scripts": { "ng": "ng", "start": "ng serve", @@ -29,10 +29,10 @@ "bootstrap": "~4.5.0", "core-js": "^3.4.8", "font-awesome": "^4.7.0", + "freehackquest-libclient-web-js": "^0.2.30", "hammerjs": "^2.0.8", "highlight.js": "^9.16.2", "jquery": "^3.5.0", - "libfhqcli-web-js": "^0.2.29", "marked": "^0.7.0", "ng2-simplemde": "^2.1.0", "ngx-ace-wrapper": "^8.0.0", diff --git a/fhq-web-user/src/app/app.module.ts b/fhq-web-user/src/app/app.module.ts index a54304c1..34c2f671 100644 --- a/fhq-web-user/src/app/app.module.ts +++ b/fhq-web-user/src/app/app.module.ts @@ -14,6 +14,7 @@ import { MatProgressBarModule, MatSnackBarModule, MatBadgeModule, + MatChipsModule, MatRippleModule } from '@angular/material'; @@ -173,6 +174,7 @@ const l10nConfig: L10nConfig = { MatProgressBarModule, MatSnackBarModule, MatBadgeModule, + MatChipsModule, MatRippleModule ], exports: [ diff --git a/fhq-web-user/src/app/pages/useful-links/useful-links.component.html b/fhq-web-user/src/app/pages/useful-links/useful-links.component.html index 7816cd3e..dfde2e6a 100644 --- a/fhq-web-user/src/app/pages/useful-links/useful-links.component.html +++ b/fhq-web-user/src/app/pages/useful-links/useful-links.component.html @@ -1,5 +1,15 @@

usefulLinks

+ + + {{ tag.name }} ({{ tag.counter }}) + + + usefulLinks - - - - - -