proca 0.1.3 → 0.4.1

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.
@@ -0,0 +1,116 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import { error, stdout, ux } from "@oclif/core/ux";
3
+ import Command from "#src/procaCommand.mjs";
4
+ import { FragmentSummary } from "#src/queries/widget.mjs";
5
+ import { gql, query } from "#src/urql.mjs";
6
+
7
+ export default class WidgetList extends Command {
8
+ static description = "list all the widgets of an org or campaign";
9
+
10
+ static examples = ["<%= config.bin %> <%= command.id %> -o <organisation>"];
11
+
12
+ static flags = {
13
+ // flag with no value (-f, --force)
14
+ ...super.globalFlags,
15
+ org: Flags.string({
16
+ char: "o",
17
+ exactlyOne: ["campaign", "org"],
18
+ description: "widgets of the organisation (coordinator or partner)",
19
+ helpValue: "<organisation name>",
20
+ // required: true,
21
+ }),
22
+ campaign: Flags.string({
23
+ char: "c",
24
+ description: "widgets of the campaign (coordinator or partner)",
25
+ helpValue: "<campaign name>",
26
+ // required: true,
27
+ }),
28
+ config: Flags.boolean({
29
+ description: "get the config",
30
+ default: false,
31
+ allowNo: true,
32
+ }),
33
+ };
34
+ fetchCampaign = async (name) => {
35
+ const Document = gql`
36
+ query SearchWidgets($campaign: String!, $withConfig: Boolean!) {
37
+ campaign (name:$campaign) { ...on PrivateCampaign {
38
+ actionPages {
39
+ ...Summary
40
+ config @include(if: $withConfig)
41
+ thankYouTemplate
42
+ thankYouTemplateRef
43
+ ...on PrivateActionPage {
44
+ supporterConfirmTemplate
45
+ }
46
+ }}
47
+ }
48
+ ${FragmentSummary}
49
+ }`;
50
+ const result = await query(Document, {
51
+ campaign: name,
52
+ withConfig: this.flags.config,
53
+ });
54
+ return result.campaign.actionPages;
55
+ };
56
+
57
+ fetchOrg = async (name) => {
58
+ const Document = gql`
59
+ query SearchWidgets($org: String!, $withConfig: Boolean!) {
60
+ org (name:$org) {
61
+ actionPages {
62
+ ...Summary
63
+ config @include(if: $withConfig)
64
+ thankYouTemplate
65
+ thankYouTemplateRef
66
+ ...on PrivateActionPage {
67
+ supporterConfirmTemplate
68
+ }
69
+ }
70
+ }
71
+ ${FragmentSummary}
72
+ }`;
73
+ const result = await query(Document, {
74
+ org: name,
75
+ withConfig: this.flags.config,
76
+ });
77
+ return result.org.actionPages;
78
+ };
79
+
80
+ simplify = (d) => {
81
+ const result = {
82
+ id: d.id,
83
+ name: d.name,
84
+ locale: d.locale,
85
+ status: d.status.toLowerCase(),
86
+ location: d.location?.startsWith("https://widget.proca.app")
87
+ ? undefined
88
+ : d.location || undefined,
89
+ // live: d.live,
90
+
91
+ // thankYouTemplate: d.thankYouTemplate || undefined,
92
+ // thankYouTemplateRef: d.thankYouTemplateRef || undefined,
93
+ // supporterConfirmTemplate: d.supporterConfirmTemplate || undefined,
94
+ };
95
+ if (d.extraSupporters > 0) {
96
+ result.extra = d.extraSupporters;
97
+ }
98
+ if (d.journey) result.journey = d.journey.join(" → ");
99
+
100
+ if (this.flags.config) {
101
+ }
102
+ return result;
103
+ };
104
+
105
+ table = (r) => {
106
+ super.table(r, null, (table) => table.sort(["id|des"]).toString());
107
+ };
108
+
109
+ async run() {
110
+ const { flags, args } = await this.parse(WidgetList);
111
+ let data = [];
112
+ if (flags.org) data = await this.fetchOrg(flags.org);
113
+ if (flags.campaign) data = await this.fetchCampaign(flags.campaign);
114
+ return this.output(data);
115
+ }
116
+ }
package/src/config.mjs CHANGED
@@ -19,7 +19,7 @@ export const get = (file) => {
19
19
  const userConfig = readFileSync(file, "utf8");
20
20
  return userConfig;
21
21
  } catch (e) {
22
- if (e.code === "ENOENT" && onMissing) {
22
+ if (e.code === "ENOENT") {
23
23
  return undefined;
24
24
  }
25
25
  throw e;
@@ -0,0 +1,14 @@
1
+ import { Config, Help } from "@oclif/core";
2
+
3
+ export default class CustomHelp extends Help {
4
+ showCommandHelp(command) {
5
+ // console.log("This will be displayed in single-command CLIs");
6
+ super.showCommandHelp(command);
7
+ }
8
+
9
+ async showHelp(argv) {
10
+ // console.log('This will be displayed in multi-command CLIs')
11
+ // Always include --all flag to show all commands
12
+ await super.showHelp([...argv, "--all"]);
13
+ }
14
+ }
@@ -0,0 +1,12 @@
1
+ import oclif from "@oclif/core";
2
+ import CustomHelp from "./help.mjs";
3
+
4
+ //console.log("hook init");
5
+
6
+ const hook = async (opts) => {
7
+ //console.log(opts);
8
+ //console.log(opts.config.helpClass, CustomHelp);
9
+ // opts.config.helpClass = CustomHelp;
10
+ };
11
+
12
+ export default hook;
@@ -1,5 +1,6 @@
1
- import { Command, Flags, ux } from "@oclif/core";
1
+ import { Args, Command, Flags, ux } from "@oclif/core";
2
2
  import debug from "debug";
3
+ import { parse as dxid, id } from "dxid";
3
4
  import Table from "easy-table";
4
5
  import fastcsv from "fast-csv";
5
6
 
@@ -9,37 +10,82 @@ import { createClient } from "#src/urql.mjs";
9
10
  export class ProcaCommand extends Command {
10
11
  static enableJsonFlag = true;
11
12
  procaConfig = { url: "https://api.proca.app/api" };
12
- format = "table"; // the default formatting
13
+ format = "human"; // the default formatting
13
14
  flags = {};
14
15
 
15
16
  static baseFlags = {
16
- table: Flags.boolean({
17
+ human: Flags.boolean({
17
18
  helpGroup: "OUTPUT", // Optional, groups it under a specific help section if desired
18
- description: "Format output as table [default]",
19
+ description: "Format output to be read on screen by a human [default]",
19
20
  default: true,
20
- exclusive: ["csv", "json"],
21
21
  }),
22
22
  json: Flags.boolean({
23
23
  helpGroup: "OUTPUT", // Optional, groups it under a specific help section if desired
24
24
  description: "Format output as json",
25
- exclusive: ["csv", "table"],
25
+ exclusive: ["human", "json"],
26
26
  }),
27
27
  csv: Flags.boolean({
28
28
  description: "Format output as csv",
29
29
  helpGroup: "OUTPUT", // Optional, groups it under a specific help section if desired
30
- exclusive: ["json", "table"],
31
30
  }),
32
31
  simplify: Flags.boolean({
33
32
  helpGroup: "OUTPUT",
34
33
  description:
35
- "flatten and filter to output only the most important attributes",
34
+ "flatten and filter to output only the most important attributes, mostly relevant for json",
36
35
  dependsOn: ["json"],
37
36
  }),
38
37
  };
39
38
 
39
+ static multiid() {
40
+ const args = {
41
+ id_name_dxid: Args.string({
42
+ ignoreStdin: true,
43
+ hidden: true,
44
+ description:
45
+ "it's better to use -i <id> or -x <dxid> or -n <name>, but you can for convenience",
46
+ }),
47
+ };
48
+ return args;
49
+ }
50
+
51
+ static flagify(params = {}) {
52
+ const flags = ProcaCommand.baseFlags;
53
+ if (params.multiid) {
54
+ flags.id = Flags.string({
55
+ char: "i",
56
+ parse: (input) => Number.parseInt(input, 10),
57
+ exclusive: ["name", "dxid"],
58
+ });
59
+ flags.dxid = Flags.string({
60
+ char: "x",
61
+ description: "dxid",
62
+ });
63
+ flags.name = Flags.string({
64
+ char: "n",
65
+ charAliases: ["o"],
66
+ description: "name",
67
+ helpValue: "<the_short_name>",
68
+ });
69
+ }
70
+ return flags;
71
+ }
72
+
73
+ async parse() {
74
+ const parsed = await super.parse();
75
+ const maybe = parsed.args.id_name_dxid;
76
+ if (maybe) {
77
+ const d = dxid(maybe, false);
78
+ if (d) parsed.flags.id = d;
79
+ else parsed.flags.name = maybe;
80
+ }
81
+ if (parsed.flags.dxid) {
82
+ parsed.flags.id = dxid(parsed.flags.dxid);
83
+ }
84
+ return parsed;
85
+ }
40
86
  async init() {
41
87
  await super.init();
42
- const { flags } = await this.parse();
88
+ const { argv, flags } = await this.parse();
43
89
  this.flags = flags;
44
90
  if (flags.json) this.format = "json";
45
91
  if (flags.csv) this.format = "csv";
@@ -55,21 +101,45 @@ export class ProcaCommand extends Command {
55
101
  createClient(userConfig);
56
102
  }
57
103
 
104
+ async catch(err) {
105
+ // Check if the error was caused by a missing flag or wrong argument format
106
+
107
+ if (
108
+ err.message.includes("Unexpected argument") ||
109
+ err.message.includes("flag")
110
+ ) {
111
+ // Try to adjust the argument as a flag
112
+ const argv = process.argv;
113
+ console.log(argv);
114
+ if (argv.includes("param")) {
115
+ // Adjusting the argument 'param' to be a flag `-id`
116
+ const paramIndex = argv.indexOf("param");
117
+ argv.splice(paramIndex, 0, "-id"); // Insert the flag `-id` before 'param'
118
+ }
119
+
120
+ // Re-run the command with modified arguments
121
+ await this.parse();
122
+ } else {
123
+ throw err;
124
+ }
125
+ }
126
+
58
127
  simplify = (d) => {
59
128
  const r = {};
60
129
  for (const [key, value] of Object.entries(d)) {
61
130
  if (key === "__typename") continue;
131
+ if (key === "config" && typeof value === "string") continue; // it's just a giant mess if not processed, let's skipt
62
132
  if (value === null) continue;
63
-
64
133
  if (typeof value === "string" || typeof value === "number") {
65
134
  r[key] = value;
66
135
  continue;
67
136
  }
68
137
 
69
- if (typeof value === "object" && value.name) {
70
- r[key] = value.name;
138
+ if (typeof value === "object") {
139
+ if (value?.name) r[key] = value.name;
71
140
  continue;
72
141
  }
142
+ r[key] = value;
73
143
  }
74
144
  return r;
75
145
  };
@@ -118,15 +188,14 @@ export class ProcaCommand extends Command {
118
188
  });
119
189
  }
120
190
 
121
- table(
122
- data,
123
- transformRow = (d, cell) => {
124
- for (const [key, value] of Object.entries(this.simplify(d))) {
125
- cell(key, value);
126
- }
127
- },
128
- print = (table) => table.toString(),
129
- ) {
191
+ table(data, transformRow, print = (table) => table.toString()) {
192
+ if (!transformRow) {
193
+ transformRow = (d, cell) => {
194
+ for (const [key, value] of Object.entries(this.simplify(d))) {
195
+ cell(key, value);
196
+ }
197
+ };
198
+ }
130
199
  const theme = this.config.theme;
131
200
  Table.prototype.pushDelimeter = function (cols) {
132
201
  // hack to change the formatting of the header
@@ -0,0 +1,12 @@
1
+ import { gql } from "#src/urql.mjs";
2
+
3
+ export const FragmentSummary = gql`fragment Summary on PrivateActionPage {
4
+ id
5
+ locale
6
+ name
7
+ journey
8
+ extraSupporters
9
+ status,
10
+ location
11
+ }
12
+ `;
package/src/urql.mjs CHANGED
@@ -6,6 +6,8 @@ import {
6
6
  gql,
7
7
  } from "urql";
8
8
 
9
+ import { GraphQLError, formatError } from "graphql";
10
+
9
11
  export let client = {
10
12
  query: () => {
11
13
  throw new Error("urql graphql not initialised, call init first");
@@ -38,7 +40,16 @@ export const createClient = (config) => {
38
40
  export const query = async (query, payload) => {
39
41
  const result = await client.query(query, payload).toPromise();
40
42
  if (result.error) {
41
- throw new Error(result.error);
43
+ console.log(formatError(result.error));
44
+ throw result.error;
45
+ }
46
+ return result.data;
47
+ };
48
+
49
+ export const mutation = async (mutation, payload) => {
50
+ const result = await client.mutation(mutation, payload).toPromise();
51
+ if (result.error) {
52
+ throw result.error;
42
53
  }
43
54
  return result.data;
44
55
  };
@@ -12,28 +12,22 @@
12
12
  // instrumentation.
13
13
  // -------------------------------------------------------------------------------
14
14
 
15
- export type ProcessLike = {
16
- argv: string[];
17
- env: { [key: string]: string | undefined };
18
- };
15
+ export function _preprocessCliFlags(process) {
16
+ process.argv.map((arg) => {
17
+ if (arg === "--dev-debug") {
18
+ let debug = "*";
19
+ const filterIndex = process.argv.indexOf("--debug-filter");
20
+ if (filterIndex > 0) {
21
+ debug = process.argv[filterIndex + 1];
19
22
 
20
- export function preprocessCliFlags(process: ProcessLike): void {
21
- process.argv.map((arg) => {
22
- if (arg === '--dev-debug') {
23
- let debug = '*';
24
- const filterIndex = process.argv.indexOf('--debug-filter');
25
- if (filterIndex > 0) {
26
- debug = process.argv[filterIndex + 1];
23
+ process.argv.splice(filterIndex, 2);
24
+ }
25
+ // convert --dev-debug into a set of environment variables
26
+ process.env.DEBUG = debug;
27
+ process.env.PROCA_ENV = "development";
27
28
 
28
- process.argv.splice(filterIndex, 2);
29
- }
30
- // convert --dev-debug into a set of environment variables
31
- process.env.DEBUG = debug;
32
- process.env.PROCA_ENV = 'development';
33
-
34
-
35
- // need to calculate indexOf --dev-debug here because it might've changed based on --debug-filter
36
- process.argv.splice(process.argv.indexOf('--dev-debug'), 1);
37
- }
38
- });
29
+ // need to calculate indexOf --dev-debug here because it might've changed based on --debug-filter
30
+ process.argv.splice(process.argv.indexOf("--dev-debug"), 1);
31
+ }
32
+ });
39
33
  }
@@ -0,0 +1,23 @@
1
+ export const getTwitter = async (org) => {
2
+ const orgName = org.config.twitter?.screen_name || org.name;
3
+ try {
4
+ const res = await fetch(
5
+ `https://twitter.proca.app/?screen_name=${orgName}`,
6
+ );
7
+
8
+ if (res.status >= 400) {
9
+ throw new Error("Bad response from twitter.proca.app");
10
+ }
11
+
12
+ const twitter = await res.json();
13
+ twitter.picture = twitter.profile_image_url_https;
14
+ twitter.profile_image_url_https = undefined;
15
+ if (twitter) org.config.twitter = twitter;
16
+ if (!org.config.description) org.config.description = twitter.description;
17
+ if (!org.config.location) org.config.location = twitter.location;
18
+ if (!org.config.url) org.config.url = twitter.url;
19
+ if (!org.title) org.title = twitter.name;
20
+ } catch (err) {
21
+ console.error(err);
22
+ }
23
+ };