Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/Actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ export class Actions {
const poll = new Poll(payload.message.blocks);
poll.vote(payload.actions[0].text.text, payload.user.id);
payload.message.blocks = poll.getBlocks();
payload.message.text = "Vote changed!";
// Sends user message if their vote was changed or blocked due to the poll being locked
const vote_text = poll.getLockedStatus() ? "You cannot vote after the poll has been locked!" : "Vote changed!";
this.wc.chat.postEphemeral({
channel: payload.channel.id,
text: vote_text, user: payload.user.id
});
// We respond with the new payload
res(payload.message);
// In case it is being slow users will see this message
Expand All @@ -51,6 +56,9 @@ export class Actions {
case "lock":
this.onLockSelected(payload, poll);
break;
case "unlock":
this.onUnlockSelected(payload,poll);
break;
case "delete":
this.onDeleteSelected(payload, poll);
break;
Expand Down Expand Up @@ -115,6 +123,16 @@ export class Actions {
this.postEphemeralOnlyAuthor("lock", "poll", payload.channel.id, payload.user.id);
}
}

private onUnlockSelected(payload: any, poll: Poll): void {
payload.message.text = "Poll unlocked!";
if (Actions.isPollAuthor(payload,poll)) {
poll.unlockpoll();
payload.message.blocks = poll.getBlocks();
} else{
this.postEphemeralOnlyAuthor("unlock","poll",payload.channel.id, payload.user.id);
}
}

private onDeleteSelected(payload: any, poll: Poll): void {
if (Actions.isPollAuthor(payload, poll)) {
Expand Down
53 changes: 31 additions & 22 deletions src/Poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,8 @@ export class Poll {

const titleBlock = Static.buildSectionBlock(mrkdwnValue);
message.push(titleBlock, Static.buildContextBlock(`Asked by: ${author}`));
const actionBlocks: ActionsBlock[] = [{ type: "actions", elements: [] }];
let actionBlockCount = 0;
// Construct all the buttons
const start = titleBlock.text!.text === parameters[0] ? 1 : 2;
for (let i = start; i < parameters.length; i++) {
if (i % 5 === 0) {
const newActionBlock: ActionsBlock = { type: "actions", elements: [] };
actionBlocks.push(newActionBlock);
actionBlockCount++;
}
// Remove special characters, should be able to remove this once slack figures itself out
parameters[i] = parameters[i].replace("&amp;", "+").replace("&lt;", "greater than ")
.replace("&gt;", "less than ");
// We set value to empty string so that it is always defined
const button: Button = { type: "button", value: " ", text: Static.buildTextElem(parameters[i]) };
actionBlocks[actionBlockCount].elements.push(button);
}
const actionBlocks = Static.buildVoteOptions(parameters,start);
// The various poll options
const selection: StaticSelect = {
type: "static_select",
Expand Down Expand Up @@ -83,8 +68,10 @@ export class Poll {
// Since its databaseless the way we know if it is anonymous or multiple is by parsing the title
this.multiple = this.checkIfMsgContains("(Multiple Answers)");
this.anonymous = this.checkIfMsgContains("(Anonymous)");
// If there's no buttons then the poll is locked
this.isLocked = this.message[3].type === "divider";
//if there is a lock symbol right below the divider, the poll is locked
if (this.message.length-1 !== this.getDividerId()) {
this.isLocked = ((this.message[this.getDividerId()+1] as SectionBlock).text as MrkdwnElement).text === ":lock:";
}
}

public getBlocks(): KnownBlock[] {
Expand All @@ -104,6 +91,23 @@ export class Poll {
return { votes, userIdIndex: votes.indexOf(userId) };
}

private getDynamicSelect(): ActionsBlock[] {
const selection: StaticSelect = {
type: "static_select",
placeholder: Static.buildTextElem("Poll Options"),
options: [
Static.buildSelectOption("Reset your vote", "reset"),
this.isLocked ? Static.buildSelectOption(":unlock: Unlock poll", "unlock") : Static.buildSelectOption(":lock: Lock poll", "lock"),
Static.buildSelectOption("Move to bottom", "bottom"),
Static.buildSelectOption("Delete poll", "delete")
]
};
if (this.anonymous) {
selection.options!.push(Static.buildSelectOption("Collect Results", "collect"));
}
return [{ type: "actions", elements: [selection] }];
}

public resetVote(userId: string): void {
this.processButtons(this.message.length, button => {
const { votes, userIdIndex } = this.getVotesAndUserIndex(button, userId);
Expand All @@ -117,6 +121,7 @@ export class Poll {
}

public vote(buttonText: string, userId: string): void {
if (this.isLocked) return;
this.processButtons(this.message.length, button => {
const { votes, userIdIndex } = this.getVotesAndUserIndex(button, userId);
if (!this.multiple && userIdIndex > -1 && button.text.text !== buttonText) {
Expand All @@ -131,13 +136,17 @@ export class Poll {
}

public lockPoll(): void {
if (this.isLocked) return;
this.isLocked = true;
this.generateVoteResults();
this.message = this.message.slice(0, 2).concat(this.message.slice(this.getDividerId() - 1));
this.message = this.message.slice(0, this.getDividerId()-1).concat(this.getDynamicSelect()).concat(this.message.slice(this.getDividerId()));
// ((this.message[2] as ActionsBlock).elements[0] as StaticSelect).options!.splice(0, 2);
}

public unlockpoll(): void {
this.isLocked = false;
this.message = this.message.slice(0,this.getDividerId()-1).concat(this.getDynamicSelect()).concat({ type: "divider" }).concat(this.message.slice(this.getDividerId()+2));
}

// Creates the message that will be sent to the poll author with the final results
public collectResults(): KnownBlock[] {
const results = this.generateResults(true);
Expand Down Expand Up @@ -179,11 +188,11 @@ export class Poll {
});
const sections = Object.keys(votes).map(key => this.buildVoteTally(overrideAnon, votes, key) as SectionBlock);
if (this.isLocked) sections.unshift(Static.buildSectionBlock(":lock:"));
return sections;
return sections.filter(f=>f !== null);
}

private generateVoteResults(): void {
// We throw out the old vote response and construct them again
// We throw out the old vote response and construct them again
this.message = this.message.slice(0, this.getDividerId() + 1).concat(this.generateResults(false));
}

Expand Down
29 changes: 24 additions & 5 deletions src/Static.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
SectionBlock, ContextBlock, PlainTextElement, Option
SectionBlock, ContextBlock, PlainTextElement, Option, ActionsBlock, Button
} from "@slack/types";

export class Static {
Expand All @@ -8,18 +8,37 @@ export class Static {
}

public static buildSectionBlock(mrkdwnValue: string): SectionBlock {
return { type: "section", text: { type: "mrkdwn", text: mrkdwnValue } };
return {type: "section", text: {type: "mrkdwn", text: mrkdwnValue}};
}

public static buildContextBlock(mrkdwnValue: string): ContextBlock {
return { type: "context", elements: [ { type: "mrkdwn", text: mrkdwnValue } ] };
return {type: "context", elements: [{type: "mrkdwn", text: mrkdwnValue}]};
}

public static buildSelectOption(text: string, value: string): Option {
return { text: this.buildTextElem(text), value: value };
return {text: this.buildTextElem(text), value: value};
}

public static buildTextElem(text: string): PlainTextElement {
return { type: "plain_text", text, emoji: true };
return {type: "plain_text", text, emoji: true};
}
public static buildVoteOptions(parameters: string [], start: number ): ActionsBlock[] {
const actionBlocks: ActionsBlock[] = [{ type: "actions", elements: [] }];
let actionBlockCount = 0;
// Construct all the buttons
for (let i = start; i < parameters.length; i++) {
if (i % 5 === 0 && i != 0) {
const newActionBlock: ActionsBlock = { type: "actions", elements: [] };
actionBlocks.push(newActionBlock);
Comment on lines +31 to +32
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just make this one line if we're not going to re-use the defined constant again.

actionBlockCount++;
}
// Remove special characters, should be able to remove this once slack figures itself out
parameters[i] = parameters[i].replace("&amp;", "+").replace("&gt;", "greater than ")
.replace("&lt;", "less than ");
// We set value to empty string so that it is always defined
const button: Button = { type: "button", value: " ", text: Static.buildTextElem(parameters[i]) };
actionBlocks[actionBlockCount].elements.push(button);
Comment on lines +39 to +40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.

}
return actionBlocks;
}
}