diff --git a/flake.lock b/flake.lock index 8cd8d0a2..4feb7112 100644 --- a/flake.lock +++ b/flake.lock @@ -845,11 +845,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1757797135, - "narHash": "sha256-zwE/e7CuPJUWKdvvTCB7iunV4E/+G0lKfv4kk/5Izdg=", + "lastModified": 1757823305, + "narHash": "sha256-goy+ZVzBAe/cN/Udsiqg7RdNA19jyJqO8x6KXnZ8Mfs=", "owner": "CHN-beta", "repo": "nixpkgs", - "rev": "1c9ddb7f7b4d79fd290561ffb3be03fb493c5c81", + "rev": "db545f2ed84e23a80610792162a7a8adc888dcae", "type": "github" }, "original": { diff --git a/flake/dev.nix b/flake/dev.nix index 487bd244..cb9d9c66 100644 --- a/flake/dev.nix +++ b/flake/dev.nix @@ -48,4 +48,11 @@ CMAKE_EXPORT_COMPILE_COMMANDS = "1"; hardeningDisable = [ "all" ]; }; + xinli = pkgs.mkShell.override { stdenv = pkgs.clang18Stdenv; } + { + inputsFrom = [ pkgs.localPackages.xinli ]; + packages = [ pkgs.clang-tools_18 ]; + CMAKE_EXPORT_COMPILE_COMMANDS = "1"; + hardeningDisable = [ "all" ]; + }; } diff --git a/packages/default.nix b/packages/default.nix index e347d646..7c10765e 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -145,6 +145,8 @@ inputs: rec speedtest = inputs.pkgs.callPackage ./speedtest.nix { src = inputs.topInputs.speedtest; }; atat = inputs.pkgs.callPackage ./atat.nix { src = inputs.topInputs.self.src.atat; }; atomkit = inputs.pkgs.callPackage ./atomkit.nix { src = inputs.topInputs.self.src.atomkit; }; + xinli = inputs.pkgs.callPackage ./xinli + { inherit biu; stdenv = inputs.pkgs.clang18Stdenv; inherit (inputs.pkgs.pkgs-unstable) httplib; }; fromYaml = content: builtins.fromJSON (builtins.readFile (inputs.pkgs.runCommand "toJSON" {} diff --git a/packages/xinli/.envrc b/packages/xinli/.envrc new file mode 100644 index 00000000..d780a0e4 --- /dev/null +++ b/packages/xinli/.envrc @@ -0,0 +1 @@ +use flake .#xinli diff --git a/packages/xinli/.gitignore b/packages/xinli/.gitignore new file mode 100644 index 00000000..5b6b0720 --- /dev/null +++ b/packages/xinli/.gitignore @@ -0,0 +1 @@ +config.yaml diff --git a/packages/xinli/CMakeLists.txt b/packages/xinli/CMakeLists.txt new file mode 100644 index 00000000..a8bc0a24 --- /dev/null +++ b/packages/xinli/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.14) +project(xinli VERSION 0.0.0 LANGUAGES CXX) +enable_testing() +include(GNUInstallDirs) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message("Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +find_package(biu REQUIRED) +find_package(httplib REQUIRED) +find_package(nlohmann_json REQUIRED) + +add_executable(xinli src/main.cpp) +target_compile_features(xinli PUBLIC cxx_std_23) +target_link_libraries(xinli PRIVATE biu::biu httplib::httplib nlohmann_json::nlohmann_json) +install(TARGETS xinli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS) +message("Imported targets: ${ImportedTargets}") +message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}") diff --git a/packages/xinli/default.nix b/packages/xinli/default.nix new file mode 100644 index 00000000..a298a805 --- /dev/null +++ b/packages/xinli/default.nix @@ -0,0 +1,7 @@ +{ lib, stdenv, cmake, pkg-config, biu, httplib, nlohmann_json }: stdenv.mkDerivation +{ + name = "xinli"; + src = ./.; + buildInputs = [ biu httplib nlohmann_json ]; + nativeBuildInputs = [ cmake pkg-config ]; +} diff --git a/packages/xinli/src/main.cpp b/packages/xinli/src/main.cpp new file mode 100644 index 00000000..b69519e0 --- /dev/null +++ b/packages/xinli/src/main.cpp @@ -0,0 +1,103 @@ +# include +# include +# include + +using namespace biu::literals; + +int main(int argc, char **argv) +{ + biu::Logger::Guard log; + + struct Job_t { std::string Type; YAML::Node Params; }; + struct { std::string Cookie; std::vector Jobs; } Config; + Config = YAML::LoadFile(argv[1]).as(); + log.debug("read cookie: {}"_f(Config.Cookie)); + + httplib::Client cli("https://xmuxg.xmu.edu.cn"); + auto get = [&](const std::string &url, httplib::Params params = {}) -> std::optional + { + biu::Logger::Guard log; + auto res = cli.Get(url, params, {{"Cookie", Config.Cookie}}); + if (res && res->status == 200) return log.rtn(res->body); + else { log.error("failed to get {}: {}"_f(url, res ? res->status : 0)); return {}; } + }; + auto post = [&](const std::string &url, const std::string &body) -> std::optional + { + biu::Logger::Guard log; + auto res = cli.Post + (url, {{"Cookie", Config.Cookie}}, body, "application/json"); + if (res && res->status == 200) return log.rtn(res->body); + else { log.error("failed to post {}: {}"_f(url, res ? res->status : 0)); return {}; } + }; + std::map> Campus = + { + {"翔安", {"1", "RESERVATION"}}, + {"思明", {"2", "RESERVATION"}}, + {"漳州", {"1588748384174", "RESERVATION"}}, + {"线上", {"1588748384174", "ONLINE"}}, + }; + + for (const auto &job : Config.Jobs) + { + if (job.Type == "AddSchedule") + { + struct { std::string Campus, Name, Date, Time; } params; + params = job.Params.as(); + if (!Campus.contains(params.Campus)) { log.error("unknown campus: {}"_f(params.Campus)); continue; } + + // 搜索老师id + auto teacherId = [&] -> std::optional + { + auto res = get + ("/api/mentality/teachers/searchResults", {{"keyword", params.Name}}); + if (!res) return {}; + for (auto teach : YAML::Load(*res)["data"]) + if (teach["name"].as() == params.Name) + return log.rtn(teach["userId"].as()); + log.error("teacher not found: {}"_f(params.Name)); + return {}; + }(); + if (!teacherId) continue; + log.debug("found teacher id: {} -> {}"_f(params.Name, *teacherId)); + + // 抓取排班表,在其中找到对应的时间段id + auto timeId = [&] -> std::optional + { + auto res = get + ( + "/api/mentality/scheduling/page/week/users", + { + {"campus", Campus[params.Campus].first}, + {"type", Campus[params.Campus].second}, + {"dateStart", params.Date}, + {"dateEnd", params.Date} + } + ); + if (!res) return {}; + for (auto time : YAML::Load(*res)["data"]) + if (time["timeQuantumStart"].as() == params.Time) + return log.rtn(time["id"].as()); + log.error("time slot not found: {}"_f(params.Time)); + return {}; + }(); + if (!timeId) continue; + log.debug("found time id: {} -> {}"_f(params.Time, *timeId)); + + // 提交增加排班的请求 + auto body = [&] + { + nlohmann::json j; + j["campus"] = Campus[params.Campus].first; + j["type"] = Campus[params.Campus].second; + j["userId"] = *teacherId; + j["isVisual"] = true; + j["dayTimeIds"] = std::vector{*timeId}; + return log.rtn(j.dump()); + }(); + auto res = post("/api/mentality/scheduling/teachers", body); + if (res) std::cout << *res << std::endl; + } + else log.error("unknown job type: {}"_f(job.Type)); + } + return 0; +}