proca 2.2.1 → 2.5.0
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.
- package/README.md +221 -32
- package/package.json +3 -1
- package/src/commands/action/add/mtt.mjs +192 -0
- package/src/commands/campaign/get.mjs +5 -3
- package/src/commands/campaign/list.mjs +3 -3
- package/src/commands/campaign/status.mjs +37 -12
- package/src/commands/contact/delete.mjs +43 -0
- package/src/commands/contact/get.mjs +137 -0
- package/src/commands/contact/list.mjs +2 -11
- package/src/commands/org/get.mjs +5 -11
- package/src/commands/org/logo.js +116 -0
- package/src/commands/service/add.mjs +14 -5
- package/src/commands/user/join.mjs +8 -11
- package/src/commands/widget/external/cron.js +63 -0
- package/src/commands/widget/external/index.mjs +132 -0
- package/src/gitCommand.mjs +173 -0
- package/src/index.d.mts +1 -0
- package/src/procaCommand.mjs +40 -12
- package/src/queries/campaign.mjs +1 -1
- package/src/urql.mjs +0 -1
|
@@ -8,8 +8,7 @@ export default class CampaignStatus extends Command {
|
|
|
8
8
|
static aliases = ["campaign:close"];
|
|
9
9
|
|
|
10
10
|
static examples = [
|
|
11
|
-
"<%= config.bin %> <%= command.id %> -name <campaign>",
|
|
12
|
-
"<%= config.bin %> <%= command.id %> -i <campaign_id>",
|
|
11
|
+
"<%= config.bin %> <%= command.id %> -name <campaign> --end=2025-01-02 --status=close",
|
|
13
12
|
];
|
|
14
13
|
|
|
15
14
|
static isCloseCommand =
|
|
@@ -18,46 +17,72 @@ export default class CampaignStatus extends Command {
|
|
|
18
17
|
this.id?.includes("close");
|
|
19
18
|
|
|
20
19
|
static flags = {
|
|
20
|
+
...this.flagify({ name: "campaign" }),
|
|
21
21
|
status: Flags.string({
|
|
22
|
-
...this.flagify({ multiid: true }),
|
|
23
22
|
description: "Status to set",
|
|
24
23
|
required: true,
|
|
25
24
|
default: this.isCloseCommand ? "close" : undefined,
|
|
26
25
|
options: ["draft", "live", "closed", "ignored"],
|
|
27
26
|
}),
|
|
27
|
+
start: Flags.string({
|
|
28
|
+
description: "start date of the campaign",
|
|
29
|
+
helpValue: "YYYY-MM-DD",
|
|
30
|
+
parse: async (input) => {
|
|
31
|
+
const date = new Date(input);
|
|
32
|
+
if (Number.isNaN(date.getTime())) {
|
|
33
|
+
throw new Error(`Invalid date: ${input}`);
|
|
34
|
+
}
|
|
35
|
+
return date;
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
end: Flags.string({
|
|
39
|
+
description: "end date of the campaign",
|
|
40
|
+
helpValue: "YYYY-MM-DD",
|
|
41
|
+
parse: async (input) => {
|
|
42
|
+
const date = new Date(input);
|
|
43
|
+
if (Number.isNaN(date.getTime())) {
|
|
44
|
+
throw new Error(`Invalid date: ${input}`);
|
|
45
|
+
}
|
|
46
|
+
return date;
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
28
49
|
};
|
|
29
50
|
|
|
30
51
|
updateStatus = async (props) => {
|
|
31
52
|
const Query = gql`
|
|
32
53
|
mutation (
|
|
33
|
-
$id: Int
|
|
54
|
+
$id: Int
|
|
34
55
|
$name: String
|
|
35
|
-
$
|
|
56
|
+
$input: CampaignInput!
|
|
36
57
|
) {
|
|
37
|
-
updateCampaign (id:$id,
|
|
58
|
+
updateCampaign (id:$id, name: $name, input: $input) {
|
|
38
59
|
name
|
|
39
60
|
org {name}
|
|
40
61
|
status
|
|
62
|
+
start
|
|
63
|
+
end
|
|
41
64
|
title
|
|
42
65
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
66
|
+
}`;
|
|
67
|
+
const input = {
|
|
68
|
+
status: props.status.toUpperCase(),
|
|
69
|
+
};
|
|
45
70
|
|
|
46
71
|
const result = await mutation(Query, {
|
|
47
72
|
// org: props.org,
|
|
48
73
|
id: props.id,
|
|
49
74
|
name: props.name,
|
|
50
|
-
|
|
75
|
+
input: input,
|
|
51
76
|
});
|
|
52
77
|
|
|
53
|
-
console.log("result", result);
|
|
54
78
|
return result.updateCampaign;
|
|
55
79
|
};
|
|
56
80
|
|
|
57
81
|
async run() {
|
|
58
|
-
const {
|
|
82
|
+
const { flags } = await this.parse();
|
|
59
83
|
|
|
60
84
|
const data = await this.updateStatus(flags);
|
|
61
|
-
|
|
85
|
+
|
|
86
|
+
return this.output(data, { single: true });
|
|
62
87
|
}
|
|
63
88
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { error, stdout, ux } from "@oclif/core/ux";
|
|
3
|
+
import { formatDistanceToNowStrict } from "date-fns";
|
|
4
|
+
import Command from "#src/procaCommand.mjs";
|
|
5
|
+
import {
|
|
6
|
+
FragmentOrg,
|
|
7
|
+
FragmentStats,
|
|
8
|
+
FragmentSummary,
|
|
9
|
+
} from "#src/queries/campaign.mjs";
|
|
10
|
+
import { gql, mutation } from "#src/urql.mjs";
|
|
11
|
+
|
|
12
|
+
export default class Delete extends Command {
|
|
13
|
+
static flags = {
|
|
14
|
+
...this.flagify({ name: "org", char: "o" }),
|
|
15
|
+
ref: Flags.string({
|
|
16
|
+
char: "c",
|
|
17
|
+
required: true,
|
|
18
|
+
description: "contact reference",
|
|
19
|
+
helpValue: "from contact get",
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
delete = async (ref, org) => {
|
|
24
|
+
const DeleteDocument = gql`mutation delete($ref: String!, $org: String!) {
|
|
25
|
+
deleteContact (contactRef: $ref, orgName: $org)
|
|
26
|
+
}`;
|
|
27
|
+
|
|
28
|
+
const r = await mutation(DeleteDocument, {
|
|
29
|
+
ref,
|
|
30
|
+
org,
|
|
31
|
+
});
|
|
32
|
+
if (r.errors) {
|
|
33
|
+
throw new Error(r.errors[0].message || "can't delete");
|
|
34
|
+
}
|
|
35
|
+
return r;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
async run() {
|
|
39
|
+
const { flags } = await this.parse();
|
|
40
|
+
const data = await this.delete(flags.ref, flags.name);
|
|
41
|
+
return this.output(data);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { error, stdout, ux } from "@oclif/core/ux";
|
|
3
|
+
import { formatDistanceToNowStrict } from "date-fns";
|
|
4
|
+
import Command from "#src/procaCommand.mjs";
|
|
5
|
+
import {
|
|
6
|
+
FragmentOrg,
|
|
7
|
+
FragmentStats,
|
|
8
|
+
FragmentSummary,
|
|
9
|
+
} from "#src/queries/campaign.mjs";
|
|
10
|
+
import { gql, query } from "#src/urql.mjs";
|
|
11
|
+
|
|
12
|
+
export default class Get extends Command {
|
|
13
|
+
static flags = {
|
|
14
|
+
...this.flagify({ name: "org", char: "o" }),
|
|
15
|
+
email: Flags.string({
|
|
16
|
+
char: "e",
|
|
17
|
+
required: true,
|
|
18
|
+
description: "email of the supporter",
|
|
19
|
+
helpValue: "<supporter@example.org>",
|
|
20
|
+
}),
|
|
21
|
+
utm: Flags.boolean({
|
|
22
|
+
description: "display the utm tracking parameters",
|
|
23
|
+
default: true,
|
|
24
|
+
allowNo: true,
|
|
25
|
+
exclusive: ["simplify"],
|
|
26
|
+
}),
|
|
27
|
+
comment: Flags.boolean({
|
|
28
|
+
description: "display the comment",
|
|
29
|
+
default: true,
|
|
30
|
+
allowNo: true,
|
|
31
|
+
exclusive: ["simplify"],
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
fetch = async (flags) => {
|
|
36
|
+
const Document = gql`
|
|
37
|
+
query (
|
|
38
|
+
$orgName: String!
|
|
39
|
+
$email: String!
|
|
40
|
+
) {
|
|
41
|
+
contacts(
|
|
42
|
+
orgName: $orgName
|
|
43
|
+
email: $email
|
|
44
|
+
) {
|
|
45
|
+
actionId
|
|
46
|
+
actionPage {
|
|
47
|
+
id
|
|
48
|
+
locale
|
|
49
|
+
name
|
|
50
|
+
}
|
|
51
|
+
actionType
|
|
52
|
+
campaign {
|
|
53
|
+
name
|
|
54
|
+
}
|
|
55
|
+
contact {
|
|
56
|
+
contactRef
|
|
57
|
+
payload
|
|
58
|
+
nonce
|
|
59
|
+
publicKey {
|
|
60
|
+
public
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
createdAt
|
|
64
|
+
customFields
|
|
65
|
+
privacy {
|
|
66
|
+
emailStatus
|
|
67
|
+
emailStatusChanged
|
|
68
|
+
givenAt
|
|
69
|
+
optIn
|
|
70
|
+
withConsent
|
|
71
|
+
}
|
|
72
|
+
tracking {
|
|
73
|
+
campaign
|
|
74
|
+
content
|
|
75
|
+
medium
|
|
76
|
+
source
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
const result = await query(Document, {
|
|
82
|
+
orgName: flags.name,
|
|
83
|
+
email: flags.email,
|
|
84
|
+
});
|
|
85
|
+
return result.contacts.map((d) => {
|
|
86
|
+
d.customFields = JSON.parse(d.customFields);
|
|
87
|
+
if (!d.contact.publicKey) {
|
|
88
|
+
const ref = d.contact.contactRef;
|
|
89
|
+
d.contact = JSON.parse(d.contact.payload);
|
|
90
|
+
d.contact.contactRef = ref;
|
|
91
|
+
} else {
|
|
92
|
+
this.error(
|
|
93
|
+
`encrypted contact we need the private key for ${d.contact.publicKey.public}`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return d;
|
|
97
|
+
});
|
|
98
|
+
// return result.exportActions;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
simplify = (d) => {
|
|
102
|
+
const result = {
|
|
103
|
+
contactRef: d.contact.contactRef,
|
|
104
|
+
firstname: d.contact.firstName,
|
|
105
|
+
country: d.contact.country,
|
|
106
|
+
email: d.contact.email,
|
|
107
|
+
type: d.actionType,
|
|
108
|
+
date: formatDistanceToNowStrict(d.createdAt),
|
|
109
|
+
campaign: !this.flags.campaign && d.campaign.name,
|
|
110
|
+
widget_id: d.actionPage.id,
|
|
111
|
+
widget: d.actionPage.name,
|
|
112
|
+
// customFields
|
|
113
|
+
};
|
|
114
|
+
if (this.flags.comment && d.customFields?.comment)
|
|
115
|
+
result.comment = d.customFields.comment;
|
|
116
|
+
if (this.flags.utm && d.tracking) {
|
|
117
|
+
result.utm_medium =
|
|
118
|
+
d.tracking.medium === "unknown" ? undefined : d.tracking.medium;
|
|
119
|
+
result.utm_source =
|
|
120
|
+
d.tracking.source === "unknown" ? undefined : d.tracking.source;
|
|
121
|
+
result.utm_campaign =
|
|
122
|
+
d.tracking.campaign === "unknown" ? undefined : d.tracking.campaign;
|
|
123
|
+
if (d.tracking.content)
|
|
124
|
+
result.utm_content =
|
|
125
|
+
d.tracking.content === "unknown" ? undefined : d.tracking.content;
|
|
126
|
+
}
|
|
127
|
+
if (d.customFields?.emailProvider)
|
|
128
|
+
result.provider = d.customFields.emailProvider;
|
|
129
|
+
return result;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
async run() {
|
|
133
|
+
const { flags } = await this.parse();
|
|
134
|
+
const data = await this.fetch(flags);
|
|
135
|
+
return this.output(data, { single: true });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -12,18 +12,9 @@ import { gql, query } from "#src/urql.mjs";
|
|
|
12
12
|
export default class List extends Command {
|
|
13
13
|
actionTypes = new Set();
|
|
14
14
|
|
|
15
|
-
static examples = ["<%= config.bin %> <%= command.id %> %pizza%"];
|
|
16
|
-
|
|
17
15
|
static flags = {
|
|
18
16
|
// flag with no value (-f, --force)
|
|
19
|
-
...
|
|
20
|
-
org: Flags.string({
|
|
21
|
-
char: "o",
|
|
22
|
-
description: "campaigns of the organisation (coordinator or partner)",
|
|
23
|
-
required: true,
|
|
24
|
-
// exactlyOne: ["org", "title"],
|
|
25
|
-
helpValue: "<organisation name>",
|
|
26
|
-
}),
|
|
17
|
+
...this.flagify({ name: "org", char: "o" }),
|
|
27
18
|
campaign: Flags.string({
|
|
28
19
|
char: "c",
|
|
29
20
|
description: "name of the campaign, % for wildchar",
|
|
@@ -138,7 +129,7 @@ export default class List extends Command {
|
|
|
138
129
|
limit: flags.limit,
|
|
139
130
|
onlyDoubleOptIn: flags.doi,
|
|
140
131
|
onlyOptIn: flags.optin,
|
|
141
|
-
orgName: flags.
|
|
132
|
+
orgName: flags.name,
|
|
142
133
|
start: flags.start,
|
|
143
134
|
});
|
|
144
135
|
return result.contacts.map((d) => {
|
package/src/commands/org/get.mjs
CHANGED
|
@@ -18,13 +18,7 @@ export default class OrgGet extends Command {
|
|
|
18
18
|
|
|
19
19
|
static flags = {
|
|
20
20
|
// flag with no value (-f, --force)
|
|
21
|
-
...this.flagify({ multiid: false }),
|
|
22
|
-
name: Flags.string({
|
|
23
|
-
char: "n",
|
|
24
|
-
charAliases: ["o"],
|
|
25
|
-
description: "name of the org",
|
|
26
|
-
helpValue: "<org name>",
|
|
27
|
-
}),
|
|
21
|
+
...this.flagify({ multiid: false, name: "org", char: "o" }),
|
|
28
22
|
config: Flags.boolean({
|
|
29
23
|
description: "display the config",
|
|
30
24
|
default: false,
|
|
@@ -113,8 +107,10 @@ export default class OrgGet extends Command {
|
|
|
113
107
|
simplify = (d) => {
|
|
114
108
|
const result = {
|
|
115
109
|
id: d.id,
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
name: d.name,
|
|
111
|
+
title: d.title,
|
|
112
|
+
url: d.config?.url,
|
|
113
|
+
logo: d.config?.logo,
|
|
118
114
|
"can targets reply?": d.replyEnabled ? true : undefined,
|
|
119
115
|
"confirm actions?": d.supporterConfirm
|
|
120
116
|
? d.supporterConfirmTemplate
|
|
@@ -142,9 +138,7 @@ export default class OrgGet extends Command {
|
|
|
142
138
|
};
|
|
143
139
|
|
|
144
140
|
async run() {
|
|
145
|
-
console.log("starting");
|
|
146
141
|
const { flags } = await this.parse();
|
|
147
|
-
console.log("flags", this.Flags);
|
|
148
142
|
|
|
149
143
|
const data = await this.fetch(flags);
|
|
150
144
|
return this.output(data);
|
|
@@ -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/org.mjs";
|
|
5
|
+
import { gql, mutation } from "#src/urql.mjs";
|
|
6
|
+
import { getOrg } from "./get.mjs";
|
|
7
|
+
|
|
8
|
+
export default class OrgLogo extends Command {
|
|
9
|
+
static description = "add a logo to the org";
|
|
10
|
+
|
|
11
|
+
static examples = ["<%= config.bin %> <%= command.id %> <name of the ngo>"];
|
|
12
|
+
|
|
13
|
+
static args = this.multiid();
|
|
14
|
+
|
|
15
|
+
static flags = {
|
|
16
|
+
// flag with no value (-f, --force)
|
|
17
|
+
...this.flagify({ multiid: false, name: "org", char: "o" }),
|
|
18
|
+
url: Flags.string({
|
|
19
|
+
description: "use that url (and update it)",
|
|
20
|
+
}),
|
|
21
|
+
update: Flags.boolean({
|
|
22
|
+
default: true,
|
|
23
|
+
allowNo: true,
|
|
24
|
+
description: "use that url (and update it)",
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
toProxyUrl = (pic) => {
|
|
29
|
+
const url = new URL(pic);
|
|
30
|
+
if (!url.hostname.endsWith("gstatic.com")) return googleUrl;
|
|
31
|
+
const sub = url.hostname.split(".")[0];
|
|
32
|
+
const domain = new URL(url.searchParams.get("url")).hostname;
|
|
33
|
+
return `https://pic.proca.app/favicon/${sub}/${domain}`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
fetchLogoUrl = async (domain) => {
|
|
37
|
+
const res = await fetch(
|
|
38
|
+
`https://www.google.com/s2/favicons?sz=128&domain=${domain}`,
|
|
39
|
+
{ redirect: "manual" }, // don't follow — we want the Location header
|
|
40
|
+
);
|
|
41
|
+
const location = res.headers.get("location");
|
|
42
|
+
if (!location) throw new Error(`No redirect for ${domain}`);
|
|
43
|
+
return this.toProxyUrl(location);
|
|
44
|
+
};
|
|
45
|
+
update = async ({ name, config }) => {
|
|
46
|
+
const input = {};
|
|
47
|
+
|
|
48
|
+
input.config = typeof config === "string" ? config : JSON.stringify(config);
|
|
49
|
+
|
|
50
|
+
const Document = gql`
|
|
51
|
+
mutation update(
|
|
52
|
+
$orgName: String!
|
|
53
|
+
$input: OrgInput!
|
|
54
|
+
) {
|
|
55
|
+
updateOrg(
|
|
56
|
+
name: $orgName
|
|
57
|
+
input: $input
|
|
58
|
+
) {
|
|
59
|
+
id, name, config
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
console.log({
|
|
66
|
+
orgName: name,
|
|
67
|
+
input,
|
|
68
|
+
});
|
|
69
|
+
const r = await mutation(Document, {
|
|
70
|
+
orgName: name,
|
|
71
|
+
input,
|
|
72
|
+
});
|
|
73
|
+
return { id: r.updateOrg };
|
|
74
|
+
} catch (e) {
|
|
75
|
+
const err = e.graphQLErrors?.[0];
|
|
76
|
+
|
|
77
|
+
if (err?.extensions?.code === "permission_denied") {
|
|
78
|
+
this.error(`permission denied to update org ${name}`);
|
|
79
|
+
}
|
|
80
|
+
throw new Error(err?.message ?? "failed to update org");
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
table = (r) => {
|
|
85
|
+
super.table(r, null, null);
|
|
86
|
+
if (this.flags.config) {
|
|
87
|
+
r.config.locales = undefined;
|
|
88
|
+
this.prettyJson(r.config);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
async run() {
|
|
93
|
+
const { flags } = await this.parse();
|
|
94
|
+
let logo;
|
|
95
|
+
let org;
|
|
96
|
+
if (flags.url) {
|
|
97
|
+
logo = await this.fetchLogoUrl(flags.url);
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
org = await getOrg(flags);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
this.output({ error: "user not a member of org", org: flags.name, logo });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!logo) logo = await this.fetchLogoUrl(org.config.url);
|
|
106
|
+
org.config.logo = logo;
|
|
107
|
+
if (flags.update) {
|
|
108
|
+
if (!org.config.url) {
|
|
109
|
+
org.config.url = flags.url;
|
|
110
|
+
}
|
|
111
|
+
const r = this.update({ name: flags.name, config: org.config });
|
|
112
|
+
return this.output(r);
|
|
113
|
+
}
|
|
114
|
+
return this.output({ logo, name: flags.name });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Flags } from "@oclif/core";
|
|
2
2
|
import Command from "#src/procaCommand.mjs";
|
|
3
|
-
import { gql, mutation
|
|
3
|
+
import { gql, mutation } from "#src/urql.mjs";
|
|
4
4
|
|
|
5
5
|
const SERVICE_NAMES = [
|
|
6
6
|
"MAILJET",
|
|
@@ -14,9 +14,19 @@ const SERVICE_NAMES = [
|
|
|
14
14
|
"SMTP",
|
|
15
15
|
].map((d) => d.toLowerCase());
|
|
16
16
|
|
|
17
|
-
export default class
|
|
17
|
+
export default class ServiceAdd extends Command {
|
|
18
18
|
static description =
|
|
19
|
-
"Set service, usually email backend for an org
|
|
19
|
+
"Set service, usually email backend for an org. the specific meaning of each param is dependant on the service. \nIf a service from that type exists, it will replace it";
|
|
20
|
+
|
|
21
|
+
// examples to add to help
|
|
22
|
+
// <%= config.bin %> resolves to the executable name
|
|
23
|
+
// <%= command.id %> resolves to the command name
|
|
24
|
+
static examples = [
|
|
25
|
+
// Examples can be simple strings
|
|
26
|
+
"<%= config.bin %> <%= command.id %> -o example_org --type system",
|
|
27
|
+
'<%= config.bin %> <%= command.id %> -o example_org --host=tls://mail.example.org:587 --user=login --password "secret" --type smtp',
|
|
28
|
+
'<%= config.bin %> <%= command.id %> -o example_org --host=ssl://mail.example.org:465 --user=login --password "secret" --type smtp',
|
|
29
|
+
];
|
|
20
30
|
|
|
21
31
|
static flags = {
|
|
22
32
|
...super.globalFlags,
|
|
@@ -29,7 +39,6 @@ export default class OrgEmail extends Command {
|
|
|
29
39
|
description: "type of the service",
|
|
30
40
|
options: SERVICE_NAMES,
|
|
31
41
|
required: true,
|
|
32
|
-
default: "system",
|
|
33
42
|
}),
|
|
34
43
|
user: Flags.string({
|
|
35
44
|
description: "credential of the account on the service",
|
|
@@ -37,7 +46,7 @@ export default class OrgEmail extends Command {
|
|
|
37
46
|
password: Flags.string({
|
|
38
47
|
description: "credential of the account on the service",
|
|
39
48
|
}),
|
|
40
|
-
host: Flags.
|
|
49
|
+
host: Flags.url({
|
|
41
50
|
description: "server of the service",
|
|
42
51
|
}),
|
|
43
52
|
path: Flags.string({
|
|
@@ -8,22 +8,19 @@ export default class UserJoinOrg extends Command {
|
|
|
8
8
|
|
|
9
9
|
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
10
10
|
|
|
11
|
+
static args = this.multiid();
|
|
12
|
+
|
|
11
13
|
static flags = {
|
|
12
|
-
|
|
14
|
+
// flag with no value (-f, --force)
|
|
15
|
+
...this.flagify({ multiid: false, name: "org", char: "o" }),
|
|
13
16
|
role: Flags.string({
|
|
14
17
|
description: "permission level in that org",
|
|
15
18
|
default: "campaigner",
|
|
16
19
|
options: ["owner", "campaigner", "coordinator", "translator"],
|
|
17
20
|
}),
|
|
18
|
-
org: Flags.string({
|
|
19
|
-
char: "o",
|
|
20
|
-
required: true,
|
|
21
|
-
description: "name of the org",
|
|
22
|
-
helpValue: "<org name>",
|
|
23
|
-
}),
|
|
24
21
|
user: Flags.string({
|
|
25
22
|
char: "u",
|
|
26
|
-
description: "email",
|
|
23
|
+
description: "email, default current user",
|
|
27
24
|
helpValue: "<user email>",
|
|
28
25
|
}),
|
|
29
26
|
};
|
|
@@ -58,7 +55,7 @@ mutation ($org: String!, $user: String!, $role: String = "campaigner") {
|
|
|
58
55
|
`;
|
|
59
56
|
const result = await mutation(Document, {
|
|
60
57
|
user: params.user,
|
|
61
|
-
org: params.
|
|
58
|
+
org: params.name,
|
|
62
59
|
role: params.role,
|
|
63
60
|
});
|
|
64
61
|
return result.addOrgUser;
|
|
@@ -69,10 +66,10 @@ mutation ($org: String!, $user: String!, $role: String = "campaigner") {
|
|
|
69
66
|
};
|
|
70
67
|
|
|
71
68
|
async run() {
|
|
72
|
-
const {
|
|
69
|
+
const { flags } = await this.parse();
|
|
73
70
|
let data = undefined;
|
|
74
71
|
if (!flags.user) {
|
|
75
|
-
data = await this.join(flags.
|
|
72
|
+
data = await this.join(flags.name);
|
|
76
73
|
} else {
|
|
77
74
|
data = await this.mutate(flags);
|
|
78
75
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Flags } from "@oclif/core";
|
|
4
|
+
import { update } from "#src/commands/widget/external/index.mjs";
|
|
5
|
+
import Command from "#src/procaCommand.mjs";
|
|
6
|
+
|
|
7
|
+
export default class CounterExternal extends Command {
|
|
8
|
+
static description =
|
|
9
|
+
"Pull all external counters and save it into a widget extra Supporter. symlink the widget json into config/counter";
|
|
10
|
+
|
|
11
|
+
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
12
|
+
|
|
13
|
+
static flags = {
|
|
14
|
+
"dry-run": Flags.boolean({
|
|
15
|
+
description: "just fetch, don't update",
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
async monitored() {
|
|
20
|
+
const dir = path.join(this.config.procaConfig.folder, "/counter");
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(dir);
|
|
23
|
+
} catch {
|
|
24
|
+
this.error(`create the folder ${dir}`);
|
|
25
|
+
}
|
|
26
|
+
const entries = await fs.readdir(dir);
|
|
27
|
+
const results = await Promise.all(
|
|
28
|
+
entries.map(async (entry) => {
|
|
29
|
+
const file = entry.split(".");
|
|
30
|
+
if (file.length !== 2) {
|
|
31
|
+
this.warn(`invalid file ${entry}`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (file[1] !== "json") {
|
|
35
|
+
this.warn(`should be a json file ${entry}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const content = JSON.parse(
|
|
39
|
+
await fs.readFile(path.join(dir, entry), "utf-8"),
|
|
40
|
+
);
|
|
41
|
+
return {
|
|
42
|
+
id: Number.parseInt(file[0]),
|
|
43
|
+
name: content.filename,
|
|
44
|
+
url: content.component.counter?.url,
|
|
45
|
+
path: content.component.counter?.path,
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
return results.flat();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async run() {
|
|
53
|
+
const { flags } = await this.parse(CounterExternal);
|
|
54
|
+
const widgets = await this.monitored();
|
|
55
|
+
if (flags["dry-run"]) return this.output(widgets);
|
|
56
|
+
const updated = await Promise.all(
|
|
57
|
+
widgets.map(async (widget) => {
|
|
58
|
+
return await update(widget);
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
return this.output(updated);
|
|
62
|
+
}
|
|
63
|
+
}
|