@yrpri/api 9.0.231 → 9.0.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/controllers/allOurIdeas.js +1 -1
  2. package/controllers/communities.cjs +282 -91
  3. package/controllers/domains.cjs +54 -8
  4. package/controllers/groups.cjs +51 -6
  5. package/controllers/points.cjs +4 -9
  6. package/controllers/posts.cjs +7 -9
  7. package/controllers/ratings.cjs +3 -6
  8. package/models/point.cjs +31 -3
  9. package/models/post.cjs +2 -3
  10. package/package.json +2 -2
  11. package/services/engine/allOurIdeas/aiHelper.d.ts +7 -4
  12. package/services/engine/allOurIdeas/aiHelper.js +34 -19
  13. package/services/engine/allOurIdeas/explainAnswersAssistant.d.ts +1 -1
  14. package/services/engine/allOurIdeas/explainAnswersAssistant.js +3 -9
  15. package/services/engine/moderation/fraud/CreateFraudAuditReport.cjs +35 -11
  16. package/services/engine/moderation/fraud/CreateFraudAuditReport.d.cts +21 -0
  17. package/services/engine/moderation/fraud/FraudBase.cjs +38 -18
  18. package/services/engine/moderation/fraud/FraudBase.d.cts +2 -0
  19. package/services/engine/moderation/fraud/FraudDeleteBase.cjs +48 -29
  20. package/services/engine/moderation/fraud/FraudDeleteBase.d.cts +8 -6
  21. package/services/engine/moderation/fraud/FraudDeleteEndorsements.cjs +5 -4
  22. package/services/engine/moderation/fraud/FraudDeleteEndorsements.d.cts +2 -2
  23. package/services/engine/moderation/fraud/FraudDeletePointQualities.cjs +3 -2
  24. package/services/engine/moderation/fraud/FraudDeletePointQualities.d.cts +1 -1
  25. package/services/engine/moderation/fraud/FraudDeletePoints.cjs +3 -2
  26. package/services/engine/moderation/fraud/FraudDeletePoints.d.cts +1 -1
  27. package/services/engine/moderation/fraud/FraudDeletePosts.cjs +3 -2
  28. package/services/engine/moderation/fraud/FraudDeleteRatings.cjs +61 -4
  29. package/services/engine/moderation/fraud/FraudGetBase.cjs +44 -20
  30. package/services/engine/moderation/fraud/FraudGetBase.d.cts +5 -0
  31. package/services/engine/moderation/fraud/FraudGetEndorsements.cjs +4 -13
  32. package/services/engine/moderation/fraud/FraudGetEndorsements.d.cts +1 -1
  33. package/services/engine/moderation/fraud/FraudGetPointQualities.cjs +3 -0
  34. package/services/engine/moderation/fraud/FraudGetPointQualities.d.cts +1 -1
  35. package/services/engine/moderation/fraud/FraudGetPoints.cjs +3 -0
  36. package/services/engine/moderation/fraud/FraudGetPoints.d.cts +1 -1
  37. package/services/engine/moderation/fraud/FraudGetPosts.cjs +17 -16
  38. package/services/engine/moderation/fraud/FraudGetPosts.d.cts +3 -3
  39. package/services/engine/moderation/fraud/FraudGetRatings.cjs +62 -30
  40. package/services/engine/moderation/fraud/FraudGetRatings.d.cts +4 -1
  41. package/services/engine/moderation/fraud/FraudRequestValidation.cjs +143 -0
  42. package/services/engine/moderation/fraud/FraudRequestValidation.d.cts +21 -0
  43. package/services/engine/moderation/fraud/FraudScannerNotifier.cjs +59 -35
  44. package/services/engine/moderation/fraud/FraudScannerNotifier.d.cts +20 -1
  45. package/services/llms/baseChatBot.d.ts +2 -0
  46. package/services/llms/baseChatBot.js +25 -9
  47. package/services/llms/imageGeneration/chatGptImageGenerator.d.ts +2 -2
  48. package/services/llms/imageGeneration/chatGptImageGenerator.js +13 -10
  49. package/services/llms/imageGeneration/collectionImageGenerator.js +31 -13
  50. package/services/llms/imageGeneration/dalleImageGenerator.d.ts +2 -2
  51. package/services/llms/imageGeneration/dalleImageGenerator.js +28 -16
  52. package/services/llms/imageGeneration/fluxImageGenerator.d.ts +2 -2
  53. package/services/llms/imageGeneration/fluxImageGenerator.js +9 -3
  54. package/services/llms/imageGeneration/iImageGenerator.d.ts +8 -1
  55. package/services/llms/imageGeneration/imageModelConfig.cjs +319 -0
  56. package/services/llms/imageGeneration/imageModelConfig.d.cts +79 -0
  57. package/services/llms/imageGeneration/imagenImageGenerator.d.ts +2 -3
  58. package/services/llms/imageGeneration/imagenImageGenerator.js +10 -10
  59. package/tests/fraudManagement.test.cjs +470 -0
  60. package/tests/fraudManagement.test.d.cts +1 -0
  61. package/tests/imageModelConfig.test.cjs +144 -0
  62. package/tests/imageModelConfig.test.d.cts +1 -0
  63. package/utils/ai_image_generation_guard.cjs +268 -0
  64. package/utils/ai_image_generation_guard.d.cts +34 -0
  65. package/utils/fingerprint_data.cjs +32 -0
  66. package/utils/fingerprint_data.d.cts +6 -0
  67. package/utils/recount_utils.cjs +53 -37
  68. package/utils/recount_utils.d.cts +7 -7
@@ -578,7 +578,7 @@ export class AllOurIdeasController {
578
578
  : `Top ${perPage} answers`;
579
579
  const swClientSocket = this.wsClients.get(wsClientSocketId);
580
580
  const aiHelper = new AiHelper(swClientSocket);
581
- await aiHelper.getAiAnalysis(questionId, analysisType.contextPrompt, choices, analysisCacheKey, req.redisClient, usedLanguageName, topOrBottomText, analysisType.label);
581
+ await aiHelper.getAiAnalysis(questionId, analysisType.contextPrompt, choices, analysisCacheKey, req.redisClient, usedLanguageName, topOrBottomText, analysisType.label, `aoi-analysis-${analysisIndex}-${analysisTypeIndex}`);
582
582
  }
583
583
  res.json({
584
584
  selectedChoices: choices,
@@ -27,6 +27,8 @@ const { countAllModeratedItemsByCommunity, } = require("../services/engine/moder
27
27
  const { isValidDbId } = require("../utils/is_valid_db_id.cjs");
28
28
  const { copyGroup, copyCommunity } = require("../utils/copy_utils.cjs");
29
29
  const { recountCommunity } = require("../utils/recount_utils.cjs");
30
+ const { normalizeImageGenerationProfileOptions, } = require("../services/llms/imageGeneration/imageModelConfig.cjs");
31
+ const { validateImageGenerationStartRequest, canPollImageGenerationJob, publicJobFields, } = require("../utils/ai_image_generation_guard.cjs");
30
32
  const getFromAnalyticsApi = require("../services/engine/analytics/manager.cjs").getFromAnalyticsApi;
31
33
  const triggerSimilaritiesTraining = require("../services/engine/analytics/manager.cjs").triggerSimilaritiesTraining;
32
34
  const sendBackAnalyticsResultsOrError = require("../services/engine/analytics/manager.cjs").sendBackAnalyticsResultsOrError;
@@ -36,6 +38,36 @@ const getPointCommunityIncludes = require("../services/engine/analytics/statsCal
36
38
  const getParsedSimilaritiesContent = require("../services/engine/analytics/manager.cjs").getParsedSimilaritiesContent;
37
39
  const getTranslatedTextsForCommunity = require("../services/utils/translation_helpers.cjs").getTranslatedTextsForCommunity;
38
40
  const updateTranslationForCommunity = require("../services/utils/translation_helpers.cjs").updateTranslationForCommunity;
41
+ const { validateFraudActionRequest, } = require("../services/engine/moderation/fraud/FraudRequestValidation.cjs");
42
+ const isFraudDetectionEnabledForCommunity = async function (communityId) {
43
+ const community = await models.Community.findOne({
44
+ where: {
45
+ id: communityId,
46
+ },
47
+ attributes: ["id", "configuration"],
48
+ });
49
+ if (!community) {
50
+ return null;
51
+ }
52
+ return !!(community.configuration && community.configuration.enableFraudDetection);
53
+ };
54
+ const ensureFraudDetectionEnabledForCommunity = async function (req, res, communityId, context) {
55
+ const enabled = await isFraudDetectionEnabledForCommunity(communityId);
56
+ if (enabled === null) {
57
+ res.sendStatus(404);
58
+ return false;
59
+ }
60
+ if (!enabled) {
61
+ log.warn("Fraud detection access denied because feature is disabled", {
62
+ context,
63
+ communityId,
64
+ userId: req.user.id,
65
+ });
66
+ res.sendStatus(403);
67
+ return false;
68
+ }
69
+ return true;
70
+ };
39
71
  var sendCommunityOrError = function (res, community, context, user, error, errorStatus) {
40
72
  if (error || !community) {
41
73
  if (errorStatus === 404 ||
@@ -732,6 +764,7 @@ const updateCommunityConfigParameters = function (req, community) {
732
764
  community.set("configuration.hideGroupListCardObjectives", truthValueFromBody(req.body.hideGroupListCardObjectives));
733
765
  community.set("configuration.alwaysHideLogoImage", truthValueFromBody(req.body.alwaysHideLogoImage));
734
766
  community.set("configuration.hideItemCount", truthValueFromBody(req.body.hideItemCount));
767
+ community.set("configuration.hideGroupTypeInList", truthValueFromBody(req.body.hideGroupTypeInList));
735
768
  community.set("configuration.recalculateCountersRecursively", truthValueFromBody(req.body.recalculateCountersRecursively));
736
769
  if (req.body.google_analytics_code && req.body.google_analytics_code != "") {
737
770
  community.google_analytics_code = req.body.google_analytics_code;
@@ -2641,37 +2674,60 @@ router.get("/:id/recursiveMap", auth.can("edit community"), async (req, res) =>
2641
2674
  res.sendStatus(500);
2642
2675
  }
2643
2676
  });
2644
- router.put("/:communityId/:type/start_report_creation", auth.can("edit community"), function (req, res) {
2645
- models.AcBackgroundJob.createJob({}, {}, (error, jobId) => {
2646
- if (error) {
2647
- log.error("Could not create backgroundJob", {
2648
- err: error,
2649
- context: "start_report_creation",
2650
- user: toJson(req.user.simple()),
2651
- });
2652
- res.sendStatus(500);
2653
- }
2654
- else {
2655
- let reportType;
2656
- if (req.params.type === "usersxls") {
2657
- reportType = "start-xls-users-community-report-generation";
2677
+ router.put("/:communityId/:type/start_report_creation", auth.can("edit community"), async function (req, res) {
2678
+ try {
2679
+ const communityId = parseInt(req.params.communityId);
2680
+ let reportType;
2681
+ if (req.params.type === "usersxls") {
2682
+ reportType = "start-xls-users-community-report-generation";
2683
+ }
2684
+ else if (req.params.type === "fraudAuditReport") {
2685
+ reportType = "start-fraud-audit-report-generation";
2686
+ }
2687
+ if (!reportType) {
2688
+ res.sendStatus(400);
2689
+ return;
2690
+ }
2691
+ if (req.params.type === "fraudAuditReport" &&
2692
+ !(await ensureFraudDetectionEnabledForCommunity(req, res, communityId, "start_report_creation"))) {
2693
+ return;
2694
+ }
2695
+ models.AcBackgroundJob.createJob({}, {
2696
+ communityId,
2697
+ userId: req.user.id,
2698
+ reportType,
2699
+ }, (error, jobId) => {
2700
+ if (error) {
2701
+ log.error("Could not create backgroundJob", {
2702
+ err: error,
2703
+ context: "start_report_creation",
2704
+ user: toJson(req.user.simple()),
2705
+ });
2706
+ res.sendStatus(500);
2658
2707
  }
2659
- else if (req.params.type === "fraudAuditReport") {
2660
- reportType = "start-fraud-audit-report-generation";
2708
+ else {
2709
+ queue.add("process-reports", {
2710
+ type: reportType,
2711
+ userId: req.user.id,
2712
+ exportType: req.params.type,
2713
+ fileEnding: req.params.fileEnding ? req.params.fileEnding : "xlsx",
2714
+ translateLanguage: req.query.translateLanguage,
2715
+ selectedFraudAuditId: req.body.selectedFraudAuditId,
2716
+ jobId: jobId,
2717
+ communityId,
2718
+ }, "critical");
2719
+ res.send({ jobId });
2661
2720
  }
2662
- queue.add("process-reports", {
2663
- type: reportType,
2664
- userId: req.user.id,
2665
- exportType: req.params.type,
2666
- fileEnding: req.params.fileEnding ? req.params.fileEnding : "xlsx",
2667
- translateLanguage: req.query.translateLanguage,
2668
- selectedFraudAuditId: req.body.selectedFraudAuditId,
2669
- jobId: jobId,
2670
- communityId: req.params.communityId,
2671
- }, "critical");
2672
- res.send({ jobId });
2673
- }
2674
- });
2721
+ });
2722
+ }
2723
+ catch (error) {
2724
+ log.error("Could not create backgroundJob", {
2725
+ err: error,
2726
+ context: "start_report_creation",
2727
+ user: toJson(req.user.simple()),
2728
+ });
2729
+ res.sendStatus(500);
2730
+ }
2675
2731
  });
2676
2732
  router.post("/:id/clone", auth.can("edit community"), function (req, res) {
2677
2733
  models.Community.findOne({
@@ -2717,58 +2773,145 @@ router.post("/:id/clone", auth.can("edit community"), function (req, res) {
2717
2773
  sendCommunityOrError(res, null, "clone", req.user, error);
2718
2774
  });
2719
2775
  });
2720
- router.get("/:communityId/:jobId/report_creation_progress", auth.can("edit community"), function (req, res) {
2721
- models.AcBackgroundJob.findOne({
2722
- where: {
2723
- id: req.params.jobId,
2724
- },
2725
- attributes: ["id", "progress", "error", "data"],
2726
- })
2727
- .then((job) => {
2776
+ router.get("/:communityId/:jobId/report_creation_progress", auth.can("edit community"), async function (req, res) {
2777
+ try {
2778
+ const communityId = parseInt(req.params.communityId);
2779
+ const jobMetadata = await models.AcBackgroundJob.findOne({
2780
+ where: {
2781
+ id: req.params.jobId,
2782
+ },
2783
+ attributes: ["id", "internal_data"],
2784
+ });
2785
+ if (!jobMetadata) {
2786
+ res.sendStatus(404);
2787
+ return;
2788
+ }
2789
+ const internalData = jobMetadata.internal_data || {};
2790
+ if (parseInt(internalData.communityId) !== communityId ||
2791
+ parseInt(internalData.userId) !== req.user.id) {
2792
+ log.warn("Report job status access denied", {
2793
+ context: "report_creation_progress",
2794
+ communityId,
2795
+ jobId: req.params.jobId,
2796
+ userId: req.user.id,
2797
+ });
2798
+ res.sendStatus(403);
2799
+ return;
2800
+ }
2801
+ if (internalData.reportType === "start-fraud-audit-report-generation" &&
2802
+ !(await ensureFraudDetectionEnabledForCommunity(req, res, communityId, "report_creation_progress"))) {
2803
+ return;
2804
+ }
2805
+ const job = await models.AcBackgroundJob.findOne({
2806
+ where: {
2807
+ id: req.params.jobId,
2808
+ },
2809
+ attributes: ["id", "progress", "error", "data"],
2810
+ });
2811
+ if (!job) {
2812
+ res.sendStatus(404);
2813
+ return;
2814
+ }
2728
2815
  res.send(job);
2729
- })
2730
- .catch((error) => {
2816
+ }
2817
+ catch (error) {
2731
2818
  log.error("Could not get backgroundJob", {
2732
2819
  err: error,
2733
2820
  context: "start_report_creation",
2734
2821
  user: toJson(req.user.simple()),
2735
2822
  });
2736
2823
  res.sendStatus(500);
2737
- });
2824
+ }
2738
2825
  });
2739
- router.put("/:communityId/:type/:selectedMethod/:collectionType/start_endorsement_fraud_action", auth.can("edit community"), function (req, res) {
2740
- models.AcBackgroundJob.createJob({}, {
2741
- idsToDelete: req.body.idsToDelete,
2742
- }, (error, jobId) => {
2743
- if (error) {
2744
- log.error("Could not create backgroundJob", {
2745
- err: error,
2746
- context: "start_report_creation",
2747
- user: toJson(req.user.simple()),
2748
- });
2749
- res.sendStatus(500);
2826
+ router.put("/:communityId/:type/:selectedMethod/:collectionType/start_endorsement_fraud_action", auth.can("edit community"), async function (req, res) {
2827
+ try {
2828
+ const communityId = parseInt(req.params.communityId);
2829
+ if (!(await ensureFraudDetectionEnabledForCommunity(req, res, communityId, "start_endorsement_fraud_action"))) {
2830
+ return;
2831
+ }
2832
+ const validation = validateFraudActionRequest({
2833
+ type: req.params.type,
2834
+ selectedMethod: req.params.selectedMethod,
2835
+ collectionType: req.params.collectionType,
2836
+ idsToDelete: req.body.idsToDelete,
2837
+ });
2838
+ if (validation.error) {
2839
+ res.status(400).send({ error: validation.error });
2840
+ return;
2841
+ }
2842
+ models.AcBackgroundJob.createJob({}, {
2843
+ idsToDelete: validation.idsToDelete,
2844
+ communityId,
2845
+ userId: req.user.id,
2846
+ }, (error, jobId) => {
2847
+ if (error) {
2848
+ log.error("Could not create backgroundJob", {
2849
+ err: error,
2850
+ context: "start_report_creation",
2851
+ user: toJson(req.user.simple()),
2852
+ });
2853
+ res.sendStatus(500);
2854
+ }
2855
+ else {
2856
+ queue.add("process-fraud-action", {
2857
+ type: req.params.type,
2858
+ collectionType: req.params.collectionType,
2859
+ selectedMethod: req.params.selectedMethod,
2860
+ userId: req.user.id,
2861
+ jobId: jobId,
2862
+ communityId,
2863
+ }, "critical");
2864
+ res.send({ jobId });
2865
+ }
2866
+ });
2867
+ }
2868
+ catch (error) {
2869
+ log.error("Could not create backgroundJob", {
2870
+ err: error,
2871
+ context: "start_report_creation",
2872
+ user: toJson(req.user.simple()),
2873
+ });
2874
+ res.sendStatus(500);
2875
+ }
2876
+ });
2877
+ router.get("/:communityId/:jobId/endorsement_fraud_action_status", auth.can("edit community"), async function (req, res) {
2878
+ try {
2879
+ const communityId = parseInt(req.params.communityId);
2880
+ if (!(await ensureFraudDetectionEnabledForCommunity(req, res, communityId, "endorsement_fraud_action_status"))) {
2881
+ return;
2750
2882
  }
2751
- else {
2752
- queue.add("process-fraud-action", {
2753
- type: req.params.type,
2754
- collectionType: req.params.collectionType,
2755
- selectedMethod: req.params.selectedMethod,
2883
+ const jobMetadata = await models.AcBackgroundJob.findOne({
2884
+ where: {
2885
+ id: req.params.jobId,
2886
+ },
2887
+ attributes: ["id", "internal_data"],
2888
+ });
2889
+ if (!jobMetadata) {
2890
+ res.sendStatus(404);
2891
+ return;
2892
+ }
2893
+ const internalData = jobMetadata.internal_data || {};
2894
+ if (parseInt(internalData.communityId) !== communityId ||
2895
+ parseInt(internalData.userId) !== req.user.id) {
2896
+ log.warn("Fraud job status access denied", {
2897
+ context: "endorsement_fraud_action_status",
2898
+ communityId,
2899
+ jobId: req.params.jobId,
2756
2900
  userId: req.user.id,
2757
- jobId: jobId,
2758
- communityId: req.params.communityId,
2759
- }, "critical");
2760
- res.send({ jobId });
2901
+ });
2902
+ res.sendStatus(403);
2903
+ return;
2904
+ }
2905
+ const job = await models.AcBackgroundJob.findOne({
2906
+ where: {
2907
+ id: req.params.jobId,
2908
+ },
2909
+ attributes: ["id", "progress", "error", "data"],
2910
+ });
2911
+ if (!job) {
2912
+ res.sendStatus(404);
2913
+ return;
2761
2914
  }
2762
- });
2763
- });
2764
- router.get("/:communityId/:jobId/endorsement_fraud_action_status", auth.can("edit community"), function (req, res) {
2765
- models.AcBackgroundJob.findOne({
2766
- where: {
2767
- id: req.params.jobId,
2768
- },
2769
- attributes: ["id", "progress", "error", "data"],
2770
- })
2771
- .then((job) => {
2772
2915
  if (job.progress === 100) {
2773
2916
  queue.add("process-fraud-action", {
2774
2917
  type: "delete-job",
@@ -2776,24 +2919,28 @@ router.get("/:communityId/:jobId/endorsement_fraud_action_status", auth.can("edi
2776
2919
  }, "critical", { delay: 30000 });
2777
2920
  }
2778
2921
  res.send(job);
2779
- })
2780
- .catch((error) => {
2922
+ }
2923
+ catch (error) {
2781
2924
  log.error("Could not get backgroundJob", {
2782
2925
  err: error,
2783
2926
  context: "endorsement_fraud_action_status",
2784
2927
  user: toJson(req.user.simple()),
2785
2928
  });
2786
2929
  res.sendStatus(500);
2787
- });
2930
+ }
2788
2931
  });
2789
- router.get("/:communityId/getFraudAudits", auth.can("edit community"), function (req, res) {
2790
- models.Community.findOne({
2791
- where: {
2792
- id: req.params.communityId,
2793
- },
2794
- attributes: ["data"],
2795
- })
2796
- .then((community) => {
2932
+ router.get("/:communityId/getFraudAudits", auth.can("edit community"), async function (req, res) {
2933
+ try {
2934
+ const communityId = parseInt(req.params.communityId);
2935
+ if (!(await ensureFraudDetectionEnabledForCommunity(req, res, communityId, "getFraudAudits"))) {
2936
+ return;
2937
+ }
2938
+ const community = await models.Community.findOne({
2939
+ where: {
2940
+ id: communityId,
2941
+ },
2942
+ attributes: ["data"],
2943
+ });
2797
2944
  if (community) {
2798
2945
  if (community.data) {
2799
2946
  res.send(community.data.fraudDeletionsAuditLogs);
@@ -2805,15 +2952,15 @@ router.get("/:communityId/getFraudAudits", auth.can("edit community"), function
2805
2952
  else {
2806
2953
  res.sendStatus(404);
2807
2954
  }
2808
- })
2809
- .catch((error) => {
2955
+ }
2956
+ catch (error) {
2810
2957
  log.error("Could not get backgroundJob", {
2811
2958
  err: error,
2812
2959
  context: "endorsement_fraud_action_status",
2813
2960
  user: toJson(req.user.simple()),
2814
2961
  });
2815
2962
  res.sendStatus(500);
2816
- });
2963
+ }
2817
2964
  });
2818
2965
  router.get("/:communityId/:type/getPlausibleSeries", auth.can("edit community marketing"), async (req, res) => {
2819
2966
  // Example: "timeseries?site_id=your-priorities&period=7d";
@@ -2966,25 +3113,60 @@ router.get("/:communityId/group_folders_simple", auth.can("edit community"), asy
2966
3113
  }
2967
3114
  });
2968
3115
  //TODO: Fix this permission back to edit
2969
- router.post("/:communityId/:start_generating/ai_image", auth.can("view community"), function (req, res) {
2970
- models.AcBackgroundJob.createJob({}, {}, (error, jobId) => {
3116
+ router.post("/:communityId/:start_generating/ai_image", auth.can("view community"), async function (req, res) {
3117
+ const imageOptions = normalizeImageGenerationProfileOptions(req.body.imageGenerationProfile, req.body.generationContext, req.body.imageType);
3118
+ if (imageOptions.error) {
3119
+ res.status(400).send({ error: imageOptions.error });
3120
+ return;
3121
+ }
3122
+ let guard;
3123
+ try {
3124
+ guard = await validateImageGenerationStartRequest(req, {
3125
+ collectionType: "community",
3126
+ collectionId: req.params.communityId,
3127
+ });
3128
+ }
3129
+ catch (error) {
3130
+ log.error("Could not validate image generation request", {
3131
+ err: error,
3132
+ context: "start_generating_ai_image",
3133
+ user: req.user ? toJson(req.user.simple()) : null,
3134
+ });
3135
+ res.sendStatus(500);
3136
+ return;
3137
+ }
3138
+ if (!guard.allowed) {
3139
+ res.status(guard.status).send(guard.body);
3140
+ return;
3141
+ }
3142
+ const internalData = {
3143
+ ...guard.internalData,
3144
+ imageGenerationProfile: imageOptions.imageGenerationProfile,
3145
+ };
3146
+ models.AcBackgroundJob.createJob({}, internalData, (error, jobId) => {
2971
3147
  if (error) {
2972
3148
  log.error("Could not create backgroundJob", {
2973
3149
  err: error,
2974
3150
  context: "start_generating_ai_image",
2975
- user: toJson(req.user.simple()),
3151
+ user: req.user ? toJson(req.user.simple()) : null,
2976
3152
  });
2977
3153
  res.sendStatus(500);
2978
3154
  }
2979
3155
  else {
2980
3156
  queue.add("process-generative-ai", {
2981
3157
  type: "collection-image",
2982
- userId: req.user.id,
3158
+ userId: guard.userId,
2983
3159
  jobId: jobId,
2984
3160
  collectionId: req.params.communityId,
2985
3161
  collectionType: "community",
2986
3162
  prompt: req.body.prompt,
2987
3163
  imageType: req.body.imageType,
3164
+ generationContext: guard.generationContext,
3165
+ imageGenerationProfile: imageOptions.imageGenerationProfile,
3166
+ imageProvider: imageOptions.imageProvider,
3167
+ imageModel: imageOptions.imageModel,
3168
+ imageSize: imageOptions.imageSize,
3169
+ imageQuality: imageOptions.imageQuality,
2988
3170
  }, "critical");
2989
3171
  res.send({ jobId });
2990
3172
  }
@@ -2992,20 +3174,29 @@ router.post("/:communityId/:start_generating/ai_image", auth.can("view community
2992
3174
  });
2993
3175
  //TODO: Fix this permission back to edit
2994
3176
  router.get("/:communityId/:jobId/poll_for_generating_ai_image", auth.can("view community"), function (req, res) {
3177
+ if (!req.user) {
3178
+ res.sendStatus(401);
3179
+ return;
3180
+ }
2995
3181
  models.AcBackgroundJob.findOne({
2996
3182
  where: {
2997
3183
  id: req.params.jobId,
2998
3184
  },
2999
- attributes: ["id", "progress", "error", "data"],
3185
+ attributes: ["id", "progress", "error", "data", "internal_data"],
3000
3186
  })
3001
3187
  .then((job) => {
3002
- res.send(job);
3188
+ if (!canPollImageGenerationJob(req, job)) {
3189
+ res.sendStatus(404);
3190
+ }
3191
+ else {
3192
+ res.send(publicJobFields(job));
3193
+ }
3003
3194
  })
3004
3195
  .catch((error) => {
3005
3196
  log.error("Could not get backgroundJob", {
3006
3197
  err: error,
3007
3198
  context: "poll_for_generating_ai_image",
3008
- user: toJson(req.user.simple()),
3199
+ user: req.user ? toJson(req.user.simple()) : null,
3009
3200
  });
3010
3201
  res.sendStatus(500);
3011
3202
  });
@@ -24,6 +24,8 @@ const getDomainIncludes = require('../services/engine/analytics/statsCalc.cjs').
24
24
  const getPointDomainIncludes = require('../services/engine/analytics/statsCalc.cjs').getPointDomainIncludes;
25
25
  const getParsedSimilaritiesContent = require('../services/engine/analytics/manager.cjs').getParsedSimilaritiesContent;
26
26
  const crypto = require('crypto');
27
+ const { normalizeImageGenerationProfileOptions, } = require("../services/llms/imageGeneration/imageModelConfig.cjs");
28
+ const { validateImageGenerationStartRequest, canPollImageGenerationJob, publicJobFields, } = require("../utils/ai_image_generation_guard.cjs");
27
29
  var sendDomainOrError = function (res, domain, context, user, error, errorStatus) {
28
30
  if (error || !domain) {
29
31
  if (errorStatus === 404 || (error && error.message && error.message.indexOf("invalid input syntax for type integer") > -1)) {
@@ -1311,21 +1313,56 @@ router.delete('/:domainId/:campaignId/delete_campaign', auth.can('edit domain'),
1311
1313
  }
1312
1314
  });
1313
1315
  //TODO: Move permission back to edit after figuring out how
1314
- router.post('/:domainId/:start_generating/ai_image', auth.can('view domain'), function (req, res) {
1315
- models.AcBackgroundJob.createJob({}, {}, (error, jobId) => {
1316
+ router.post('/:domainId/:start_generating/ai_image', auth.can('view domain'), async function (req, res) {
1317
+ const imageOptions = normalizeImageGenerationProfileOptions(req.body.imageGenerationProfile, req.body.generationContext, req.body.imageType);
1318
+ if (imageOptions.error) {
1319
+ res.status(400).send({ error: imageOptions.error });
1320
+ return;
1321
+ }
1322
+ let guard;
1323
+ try {
1324
+ guard = await validateImageGenerationStartRequest(req, {
1325
+ collectionType: "domain",
1326
+ collectionId: req.params.domainId,
1327
+ });
1328
+ }
1329
+ catch (error) {
1330
+ log.error('Could not validate image generation request', {
1331
+ err: error,
1332
+ context: 'start_generating_ai_image',
1333
+ user: req.user ? toJson(req.user.simple()) : null
1334
+ });
1335
+ res.sendStatus(500);
1336
+ return;
1337
+ }
1338
+ if (!guard.allowed) {
1339
+ res.status(guard.status).send(guard.body);
1340
+ return;
1341
+ }
1342
+ const internalData = {
1343
+ ...guard.internalData,
1344
+ imageGenerationProfile: imageOptions.imageGenerationProfile,
1345
+ };
1346
+ models.AcBackgroundJob.createJob({}, internalData, (error, jobId) => {
1316
1347
  if (error) {
1317
- log.error('Could not create backgroundJob', { err: error, context: 'start_generating_ai_image', user: toJson(req.user.simple()) });
1348
+ log.error('Could not create backgroundJob', { err: error, context: 'start_generating_ai_image', user: req.user ? toJson(req.user.simple()) : null });
1318
1349
  res.sendStatus(500);
1319
1350
  }
1320
1351
  else {
1321
1352
  queue.add('process-generative-ai', {
1322
1353
  type: "collection-image",
1323
- userId: req.user.id,
1354
+ userId: guard.userId,
1324
1355
  jobId: jobId,
1325
1356
  collectionId: req.params.domainId,
1326
1357
  collectionType: "domain",
1327
1358
  prompt: req.body.prompt,
1328
- imageType: req.body.imageType
1359
+ imageType: req.body.imageType,
1360
+ generationContext: guard.generationContext,
1361
+ imageGenerationProfile: imageOptions.imageGenerationProfile,
1362
+ imageProvider: imageOptions.imageProvider,
1363
+ imageModel: imageOptions.imageModel,
1364
+ imageSize: imageOptions.imageSize,
1365
+ imageQuality: imageOptions.imageQuality
1329
1366
  }, 'critical');
1330
1367
  res.send({ jobId });
1331
1368
  }
@@ -1333,15 +1370,24 @@ router.post('/:domainId/:start_generating/ai_image', auth.can('view domain'), fu
1333
1370
  });
1334
1371
  //TODO: Move permission back to edit after figuring out how
1335
1372
  router.get('/:domainId/:jobId/poll_for_generating_ai_image', auth.can('view domain'), function (req, res) {
1373
+ if (!req.user) {
1374
+ res.sendStatus(401);
1375
+ return;
1376
+ }
1336
1377
  models.AcBackgroundJob.findOne({
1337
1378
  where: {
1338
1379
  id: req.params.jobId
1339
1380
  },
1340
- attributes: ['id', 'progress', 'error', 'data']
1381
+ attributes: ['id', 'progress', 'error', 'data', 'internal_data']
1341
1382
  }).then(job => {
1342
- res.send(job);
1383
+ if (!canPollImageGenerationJob(req, job)) {
1384
+ res.sendStatus(404);
1385
+ }
1386
+ else {
1387
+ res.send(publicJobFields(job));
1388
+ }
1343
1389
  }).catch(error => {
1344
- log.error('Could not get backgroundJob', { err: error, context: 'poll_for_generating_ai_image', user: toJson(req.user.simple()) });
1390
+ log.error('Could not get backgroundJob', { err: error, context: 'poll_for_generating_ai_image', user: req.user ? toJson(req.user.simple()) : null });
1345
1391
  res.sendStatus(500);
1346
1392
  });
1347
1393
  });