Skip to content

Commit

Permalink
Merge branch 'master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlowjk authored Jun 4, 2022
2 parents 49cceff + b8a5a34 commit a7ef5ad
Show file tree
Hide file tree
Showing 65 changed files with 1,116 additions and 536 deletions.
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: category.Bug
assignees: ''
---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**

- OS: [e.g. Windows 11]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE/custom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'category.Feature'
assignees: ''
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
2 changes: 1 addition & 1 deletion e2e/spec/login/login.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("CATcher's Login Page", () => {
});

it('displays "CATcher" in header bar', async () => {
expect(await page.getTitle()).toEqual(`CATcher v${AppConfig.version}\nreceipt`);
expect(await page.getTitle()).toEqual(`CATcher v${AppConfig.version}\nreceipt\nmail`);
});

it('allows users to authenticate themselves', async () => {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"apollo-client": "^2.6.0",
"apollo-link": "^1.2.14",
"apollo-link-context": "^1.0.20",
"arcsecond": "^4.1.0",
"core-js": "^3.16.4",
"diff-match-patch": "^1.0.4",
"dompurify": "^2.3.1",
Expand All @@ -67,6 +68,7 @@
"karma-spec-reporter": "0.0.32",
"moment": "^2.24.0",
"ngx-markdown": "^8.2.1",
"ngx-mat-select-search": "^1.8.0",
"node-fetch": "^2.6.0",
"rxjs": "6.5.3",
"tslib": "^1.9.0",
Expand Down
2 changes: 1 addition & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ import { SharedModule } from './shared/shared.module';
{
provide: IssueService,
useFactory: IssueServiceFactory,
deps: [GithubService, UserService, PhaseService, ElectronService, DataService]
deps: [GithubService, UserService, PhaseService, ElectronService, DataService, LoggingService]
},
{
provide: ErrorHandler,
Expand Down
36 changes: 19 additions & 17 deletions src/app/core/models/issue.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ export class Issue {
issue.teamAssigned = teamData;
issue.assignees = githubIssue.assignees.map((assignee) => assignee.login);

issue.teamResponseError = template.parseError;
issue.teamResponseError = template.parseFailure;
issue.issueComment = template.comment;
issue.teamResponse = template.teamResponse && Issue.updateTeamResponse(template.teamResponse.content);
issue.duplicateOf = template.duplicateOf && template.duplicateOf.issueNumber;
issue.teamResponse = template.teamResponse;
issue.duplicateOf = template.duplicateOf;
issue.duplicated = issue.duplicateOf !== undefined && issue.duplicateOf !== null;

return issue;
Expand All @@ -150,11 +150,11 @@ export class Issue {
const teamAcceptedTemplate = new TeamAcceptedTemplate(githubIssue.comments);

issue.githubComments = githubIssue.comments;
issue.testerResponseError = testerResponseTemplate.parseError && !teamAcceptedTemplate.teamAccepted;
issue.testerResponseError = testerResponseTemplate.parseFailure && teamAcceptedTemplate.parseFailure;
issue.teamAccepted = teamAcceptedTemplate.teamAccepted;
issue.issueComment = testerResponseTemplate.comment;
issue.teamResponse = testerResponseTemplate.teamResponse && Issue.updateTeamResponse(testerResponseTemplate.teamResponse.content);
issue.testerResponses = testerResponseTemplate.testerResponse && testerResponseTemplate.testerResponse.testerResponses;
issue.teamResponse = testerResponseTemplate.teamResponse;
issue.testerResponses = testerResponseTemplate.testerResponses;
issue.testerDisagree = testerResponseTemplate.testerDisagree;

issue.teamChosenSeverity = testerResponseTemplate.teamChosenSeverity || null;
Expand All @@ -170,13 +170,13 @@ export class Issue {

issue.githubComments = githubIssue.comments;
issue.teamAssigned = teamData;
issue.description = issueTemplate.description.content;
issue.teamResponse = issueTemplate.teamResponse && Issue.updateTeamResponse(issueTemplate.teamResponse.content);
issue.issueDisputes = issueTemplate.dispute.disputes;
issue.description = issueTemplate.description;
issue.teamResponse = issueTemplate.teamResponse;
issue.issueDisputes = issueTemplate.disputes;

if (todoTemplate.moderation && todoTemplate.comment) {
issue.issueDisputes = todoTemplate.moderation.disputesToResolve.map((dispute, i) => {
dispute.description = issueTemplate.dispute.disputes[i].description;
if (todoTemplate.disputesToResolve && todoTemplate.comment) {
issue.issueDisputes = todoTemplate.disputesToResolve.map((dispute, i) => {
dispute.description = issueTemplate.disputes[i].description;
return dispute;
});
issue.issueComment = todoTemplate.comment;
Expand Down Expand Up @@ -240,8 +240,8 @@ export class Issue {
updateTesterResponse(githubComment: GithubComment): void {
const template = new TesterResponseTemplate([githubComment]);
this.issueComment = template.comment;
this.teamResponse = template.teamResponse && template.teamResponse.content;
this.testerResponses = template.testerResponse && template.testerResponse.testerResponses;
this.teamResponse = template.teamResponse;
this.testerResponses = template.testerResponses;
}

/**
Expand All @@ -251,7 +251,7 @@ export class Issue {
updateDispute(githubComment: GithubComment): void {
const todoTemplate = new TutorModerationTodoTemplate([githubComment]);
this.issueComment = todoTemplate.comment;
this.issueDisputes = todoTemplate.moderation.disputesToResolve.map((dispute, i) => {
this.issueDisputes = todoTemplate.disputesToResolve.map((dispute, i) => {
dispute.description = this.issueDisputes[i].description;
return dispute;
});
Expand All @@ -272,8 +272,10 @@ export class Issue {
// Template url: https://github.com/CATcher-org/templates#tutor-moderation
createGithubTutorResponse(): string {
let tutorResponseString = '# Tutor Moderation\n\n';
for (const issueDispute of this.issueDisputes) {
tutorResponseString += issueDispute.toTutorResponseString();
if (this.issueDisputes !== undefined) {
for (const issueDispute of this.issueDisputes) {
tutorResponseString += issueDispute.toTutorResponseString();
}
}
return tutorResponseString;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { char, choice, coroutine, everyCharUntil, str, whitespace } = require('arcsecond');

const TEAM_RESPONSE_HEADER = "# Team's Response";
const DEFAULT_TEAM_RESPONSE = 'No details provided by team.';

export function buildTeamResponseSectionParser(nextHeader: string) {
return coroutine(function* () {
yield str(TEAM_RESPONSE_HEADER);
yield whitespace;
const teamResponse = yield everyCharUntil(str(nextHeader));
return teamResponse.trim() ? teamResponse.trim() : DEFAULT_TEAM_RESPONSE;
});
}

export function buildCheckboxParser(description: string) {
return coroutine(function* () {
yield str('- [');
const checkbox = yield choice([char('x'), whitespace]);
yield str('] ' + description);

return checkbox === 'x';
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IssueDispute } from '../../issue-dispute.model';

const { coroutine, everyCharUntil, optionalWhitespace, str } = require('arcsecond');

const SECTION_TITLE_PREFIX = '## :question: ';
const TEAM_SAYS_HEADER = '### Team says:';
const LINE_SEPARATOR = '-------------------';

export const IssueDisputeSectionParser = coroutine(function* () {
yield str(SECTION_TITLE_PREFIX);
const title = yield everyCharUntil(str(TEAM_SAYS_HEADER));

const description = yield everyCharUntil(str(LINE_SEPARATOR));
yield str(LINE_SEPARATOR);
yield optionalWhitespace;

return new IssueDispute(title.trim(), description.trim());
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Checkbox } from '../../checkbox.model';
import { IssueDispute } from '../../issue-dispute.model';
import { buildCheckboxParser } from './common-parsers.model';

const { coroutine, everyCharUntil, lookAhead, optionalWhitespace, str, whitespace } = require('arcsecond');

const SECTION_TITLE_PREFIX = '## :question: ';
const DONE_CHECKBOX_DESCRIPTION = 'Done';
const LINE_SEPARATOR = '-------------------';

export const DoneCheckboxParser = buildCheckboxParser(DONE_CHECKBOX_DESCRIPTION);

export const ModerationSectionParser = coroutine(function* () {
yield str(SECTION_TITLE_PREFIX);
const title = yield everyCharUntil(str('- [')); // every char until the done checkbox

const description = yield lookAhead(everyCharUntil(str(LINE_SEPARATOR)));

const doneCheckboxValue = yield DoneCheckboxParser;
yield whitespace;
const tutorResponse = yield everyCharUntil(str(LINE_SEPARATOR));
yield str(LINE_SEPARATOR);
yield optionalWhitespace;

const dispute = new IssueDispute(title.trim(), description.trim());
dispute.todo = new Checkbox(DONE_CHECKBOX_DESCRIPTION, doneCheckboxValue);
dispute.tutorResponse = tutorResponse.trim();

return dispute;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { buildCheckboxParser } from './common-parsers.model';

const {
between,
coroutine,
everyCharUntil,
letters,
lookAhead,
optionalWhitespace,
pipeParsers,
possibly,
str,
whitespace
} = require('arcsecond');

const SECTION_TITLE_PREFIX = '## :question: Issue ';
const TEAM_CHOSE_PREFIX = 'Team chose ';
const TESTER_CHOSE_PREFIX = 'Originally ';
const DISAGREE_CHECKBOX_DESCRIPTION = 'I disagree';
const DISAGREEMENT_REASON_PREFIX = '**Reason for disagreement:** ';
const LINE_SEPARATOR = '-------------------';
const DUPLICATE_STATUS_MESSAGE =
"Team chose to mark this issue as a duplicate of another issue (as explained in the _**Team's response**_ above)";

export const DisagreeCheckboxParser = buildCheckboxParser(DISAGREE_CHECKBOX_DESCRIPTION);

function buildExtractResponseParser(category: string) {
return between(str('[`' + category + '.'))(str('`]'))(letters);
}

function buildTeamResponseParser(category: string) {
const extractResponseParser = buildExtractResponseParser(category);

return pipeParsers([str(TEAM_CHOSE_PREFIX), extractResponseParser]);
}

function buildTesterResponseParser(category: string) {
const extractResponseParser = buildExtractResponseParser(category);

return pipeParsers([str(TESTER_CHOSE_PREFIX), extractResponseParser]);
}

export const DisagreeReasonParser = coroutine(function* () {
yield str(DISAGREEMENT_REASON_PREFIX);
const reasonForDisagreement = yield everyCharUntil(str(LINE_SEPARATOR));
yield str(LINE_SEPARATOR);

return reasonForDisagreement.trim();
});

// Issue duplicate section has a different format than the other three
const DuplicateSectionParser = coroutine(function* () {
yield str('status');
yield whitespace;
yield str(DUPLICATE_STATUS_MESSAGE);
yield whitespace;

const disagreeCheckboxValue = yield DisagreeCheckboxParser;
yield whitespace;
const reasonForDisagreement = yield DisagreeReasonParser;

return {
disagreeCheckboxValue: disagreeCheckboxValue,
reasonForDisagreement: reasonForDisagreement
};
});

export const TesterResponseSectionParser = coroutine(function* () {
// section title
yield str(SECTION_TITLE_PREFIX);
const title = yield letters;
yield whitespace;

if (title === 'duplicate') {
const dupSectionResult = yield DuplicateSectionParser;
yield optionalWhitespace;

return {
title: title + ' status',
description: DUPLICATE_STATUS_MESSAGE,
teamChose: null,
testerChose: null,
disagreeCheckboxValue: dupSectionResult.disagreeCheckboxValue,
reasonForDisagreement: dupSectionResult.reasonForDisagreement
};
}

const description = yield lookAhead(everyCharUntil(DisagreeCheckboxParser));

// team and tester response
const teamResponseParser = buildTeamResponseParser(title);
const testerResponseParser = buildTesterResponseParser(title);

const teamChose = yield teamResponseParser;
yield whitespace;
// response section does not have tester response
const testerChose = yield possibly(testerResponseParser);
yield optionalWhitespace;

const disagreeCheckboxValue = yield DisagreeCheckboxParser;
yield whitespace;
const reasonForDisagreement = yield DisagreeReasonParser;
yield optionalWhitespace;

return {
title: title,
description: description.trim(),
teamChose: teamChose,
testerChose: testerChose,
disagreeCheckboxValue: disagreeCheckboxValue,
reasonForDisagreement: reasonForDisagreement
};
});

This file was deleted.

Loading

0 comments on commit a7ef5ad

Please sign in to comment.