Skip to content

Commit

Permalink
official feed in add feed form
Browse files Browse the repository at this point in the history
  • Loading branch information
Alessandro100 committed Nov 12, 2024
1 parent 276fbe6 commit 0357784
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 13 deletions.
2 changes: 2 additions & 0 deletions functions/packages/feed-form/src/__tests__/feed-form.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {type FeedSubmissionFormRequestBody} from "../impl/types";
const sampleRequestBodyGTFS: FeedSubmissionFormRequestBody = {
name: "Sample Feed",
isOfficialProducer: "yes",
isOfficialFeed: "yes",
dataType: "gtfs",
transitProviderName: "Sample Transit Provider",
feedLink: "https://example.com/feed",
Expand Down Expand Up @@ -137,6 +138,7 @@ describe("Feed Form Implementation", () => {
[SheetCol.LinkToAssociatedGTFS]:
sampleRequestBodyGTFS.gtfsRelatedScheduleLink,
[SheetCol.LogoPermission]: sampleRequestBodyGTFS.hasLogoPermission,
[SheetCol.OfficialFeedSource]: sampleRequestBodyGTFS.isOfficialFeed,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe("buildGithubIssueBody", () => {
it("should generate content for basic form data with GTFS feed", () => {
const formData: FeedSubmissionFormRequestBody = {
isOfficialProducer: "yes",
isOfficialFeed: "yes",
dataType: "gtfs",
transitProviderName: "Test Agency",
name: "Test Agency",
Expand Down Expand Up @@ -64,6 +65,7 @@ describe("buildGithubIssueBody", () => {
it("should handle optional location fields gracefully", () => {
const formData: FeedSubmissionFormRequestBody = {
isOfficialProducer: "no",
isOfficialFeed: "yes",
dataType: "gtfs",
transitProviderName: "Test Agency",
name: "Test Agency",
Expand Down Expand Up @@ -111,6 +113,7 @@ describe("buildGithubIssueBody", () => {
it("should handle non-GTFS data types (tu, vp, sa)", () => {
const formData: FeedSubmissionFormRequestBody = {
isOfficialProducer: "yes",
isOfficialFeed: "yes",
dataType: "gtfs_rt",
transitProviderName: "Test Agency",
name: "Test Agency",
Expand Down Expand Up @@ -159,6 +162,7 @@ describe("buildGithubIssueBody", () => {
it("should handle missing authentication details", () => {
const formData: FeedSubmissionFormRequestBody = {
isOfficialProducer: "",
isOfficialFeed: "yes",
dataType: "gtfs",
transitProviderName: "Test Agency",
name: "Test Agency",
Expand Down
37 changes: 28 additions & 9 deletions functions/packages/feed-form/src/impl/feed-form-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ export const writeToSheet = async (
process.env.GITHUB_TOKEN
);
}
await sendSlackWebhook(sheetId, githubIssueUrl);
await sendSlackWebhook(
sheetId,
githubIssueUrl,
formData.isOfficialFeed === "yes"
);
return {message: "Data written to the new sheet successfully!"};
} catch (error) {
logger.error("Error writing to sheet:", error);
Expand Down Expand Up @@ -81,6 +85,7 @@ export enum SheetCol {
UserInterview = "User interview email",
DataProducerEmail = "Data producer email",
OfficialProducer = "Are you the official producer or transit agency responsible for this data?",
OfficialFeedSource = "Is Official Feed Source",
ToolsAndSupport = "What tools and support do you use to create your GTFS data?",
LinkToAssociatedGTFS = "Link to associated GTFS Schedule feed",
LogoPermission = "Do we have permission to share your logo on https://mobilitydatabase.org/contribute?",
Expand Down Expand Up @@ -186,6 +191,7 @@ export function buildFeedRow(
[SheetCol.UserInterview]: formData.userInterviewEmail ?? "",
[SheetCol.DataProducerEmail]: formData.dataProducerEmail ?? "",
[SheetCol.OfficialProducer]: formData.isOfficialProducer,
[SheetCol.OfficialFeedSource]: formData.isOfficialFeed ?? "",
[SheetCol.ToolsAndSupport]: formData.whatToolsUsedText ?? "",
[SheetCol.LinkToAssociatedGTFS]: formData.gtfsRelatedScheduleLink ?? "",
[SheetCol.LogoPermission]: formData.hasLogoPermission,
Expand All @@ -196,11 +202,20 @@ export function buildFeedRow(
* Sends a Slack webhook message to the configured Slack webhook URL
* @param {string} spreadsheetId The ID of the Google Sheet
* @param {string} githubIssueUrl The URL of the created GitHub issue
* @param {boolean} isOfficialSource Whether the feed is an official source
*/
async function sendSlackWebhook(spreadsheetId: string, githubIssueUrl: string) {
async function sendSlackWebhook(
spreadsheetId: string,
githubIssueUrl: string,
isOfficialSource: boolean
) {
const slackWebhookUrl = process.env.SLACK_WEBHOOK_URL;
const sheetUrl = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/edit`;
if (slackWebhookUrl !== undefined && slackWebhookUrl !== "") {
let headerText = "New Feed Added";
if (isOfficialSource) {
headerText += " 🔹 Official Source";
}
const linksElement = [
{
type: "emoji",
Expand Down Expand Up @@ -237,7 +252,8 @@ async function sendSlackWebhook(spreadsheetId: string, githubIssueUrl: string) {
type: "header",
text: {
type: "plain_text",
text: "New Feed Added",
text: headerText,
emoji: true,
},
},
{
Expand All @@ -259,11 +275,11 @@ async function sendSlackWebhook(spreadsheetId: string, githubIssueUrl: string) {
],
},
{
"type": "rich_text",
"elements": [
type: "rich_text",
elements: [
{
"type": "rich_text_section",
"elements": linksElement,
type: "rich_text_section",
elements: linksElement,
},
],
},
Expand Down Expand Up @@ -292,9 +308,12 @@ async function createGithubIssue(
): Promise<string> {
const githubRepoUrlIssue =
"https://api.github.com/repos/MobilityData/mobility-database-catalogs/issues";
const issueTitle =
let issueTitle =
"New Feed Added" +
(formData.transitProviderName ? `: ${formData.transitProviderName}` : "");
if (formData.isOfficialFeed === "yes") {
issueTitle += " - Official Feed";
}
const issueBody = buildGithubIssueBody(formData, spreadsheetId);
try {
const response = await axios.post(
Expand Down Expand Up @@ -353,7 +372,7 @@ export function buildGithubIssueBody(
${formData.isUpdatingFeed === "yes" ? "Feed update" : "New feed"}`;

if (formData.name) {
content += `
content += `
#### Name
${formData.name}`;
Expand Down
1 change: 1 addition & 0 deletions functions/packages/feed-form/src/impl/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type AuthTypes =

export interface FeedSubmissionFormRequestBody {
isOfficialProducer: YesNoFormInput;
isOfficialFeed: "yes" | "no" | "unsure" | undefined;
dataType: "gtfs" | "gtfs_rt";
transitProviderName?: string;
feedLink?: string;
Expand Down
6 changes: 6 additions & 0 deletions web-app/cypress/e2e/addFeedForm.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('Add Feed Form', () => {
cy.get('[data-cy=isOfficialProducerYes]').click({
force: true,
});
cy.muiDropdownSelect('[data-cy=isOfficialFeed]', 'yes');
cy.get('[data-cy=feedLink] input').type('https://example.com/feed', {
force: true,
});
Expand All @@ -49,6 +50,7 @@ describe('Add Feed Form', () => {

it('should submit a new gtfs realtime feed as not official producer', () => {
cy.get('[data-cy=isOfficialProducerNo]').click();
cy.muiDropdownSelect('[data-cy=isOfficialFeed]', 'no');
cy.muiDropdownSelect('[data-cy=dataType]', 'gtfs_rt');
cy.get('[data-cy=submitFirstStep]').click();
cy.url().should('include', '/contribute?step=2');
Expand All @@ -70,12 +72,14 @@ describe('Add Feed Form', () => {
it('should display errors for gtfs feed', () => {
cy.muiDropdownSelect('[data-cy=isUpdatingFeed]', 'yes');
cy.get('[data-cy=submitFirstStep]').click();
cy.assetMuiError('[data-cy=isOfficialFeedLabel]');
cy.assetMuiError('[data-cy=isOfficialProducerLabel]');
cy.assetMuiError('[data-cy=feedLinkLabel]');
cy.assetMuiError('[data-cy=oldFeedLabel]');
cy.location('pathname').should('eq', '/contribute');
// Step 1 values
cy.get('[data-cy=isOfficialProducerYes]').click();
cy.muiDropdownSelect('[data-cy=isOfficialFeed]', 'yes');
cy.get('[data-cy=feedLink] input').type('https://example.com/feed', {
force: true,
});
Expand Down Expand Up @@ -106,9 +110,11 @@ describe('Add Feed Form', () => {
cy.muiDropdownSelect('[data-cy=dataType]', 'gtfs_rt');
cy.get('[data-cy=submitFirstStep]').click();
cy.assetMuiError('[data-cy=isOfficialProducerLabel]');
cy.assetMuiError('[data-cy=isOfficialFeedLabel]');
cy.location('pathname').should('eq', '/contribute');
// Step 1 values
cy.get('[data-cy=isOfficialProducerYes]').click();
cy.muiDropdownSelect('[data-cy=isOfficialFeed]', 'yes');
cy.muiDropdownSelect('[data-cy=isUpdatingFeed]', 'yes');
cy.get('[data-cy=submitFirstStep]').click();
// Step 2
Expand Down
3 changes: 2 additions & 1 deletion web-app/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"no": "No",
"required": "This field is required",
"submit": "Submit",
"select": "Select"
"select": "Select",
"notSure": "Not sure"
},
"country": "Country",
"chooseCountry": "Choose a country",
Expand Down
3 changes: 3 additions & 0 deletions web-app/public/locales/en/feeds.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"signUpAction": "Sign up for an account",
"loginSuccess": "You were successfully logged in, you can now add or update a feed.",
"dataTypeRequired": "Data format required",
"isOfficialFeedRequired": "Official feed required",
"feedLinkRequired": "Feed link required",
"oldFeedLinkRequired": "Old feed link required",
"dataProducerEmailRequired": "Data producer email required",
Expand Down Expand Up @@ -59,6 +60,8 @@
"boundingBoxTitle": "Bounding box from stops.txt",
"unableToGenerateBoundingBox": "Unable to generate bounding box.",
"areYouOfficialProducer": "Are you the official producer or transit agency responsible for this data ?",
"isOfficialSource": "Is the Official Source",
"isOfficialSourceDetails": "Select \"Yes\" if the inputed feed is the official source of information by the transit provider and should be used to display to riders",
"feedLink": "Feed Link",
"areYouUpdatingFeed": "Are you updating a feed?",
"oldFeedLink": "Old Feed Link",
Expand Down
41 changes: 38 additions & 3 deletions web-app/src/app/screens/FeedSubmission/Form/FirstStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import { type YesNoFormInput, type FeedSubmissionFormFormInput } from '.';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { isValidFeedLink } from '../../../services/feeds/utils';
import FormLabelDescription from './components/FormLabelDescription';

export interface FeedSubmissionFormFormInputFirstStep {
isOfficialProducer: YesNoFormInput;
isOfficialFeed: 'yes' | 'no' | 'unsure' | undefined;
dataType: 'gtfs' | 'gtfs_rt';
transitProviderName?: string;
feedLink?: string;
Expand All @@ -51,6 +53,7 @@ export default function FormFirstStep({
} = useForm<FeedSubmissionFormFormInputFirstStep>({
defaultValues: {
isOfficialProducer: initialValues.isOfficialProducer,
isOfficialFeed: initialValues.isOfficialFeed,
dataType: initialValues.dataType,
transitProviderName: initialValues.transitProviderName,
feedLink: initialValues.feedLink,
Expand Down Expand Up @@ -136,15 +139,47 @@ export default function FormFirstStep({
<Grid item sx={{ '&.MuiGrid-item': { pt: '4px' } }}>
<FormControl
component='fieldset'
error={errors.dataType !== undefined}
error={errors.isOfficialFeed !== undefined}
>
<FormLabel required data-cy='isOfficialFeedLabel'>
{t('isOfficialSource')}
</FormLabel>
<FormLabelDescription>
{t('isOfficialSourceDetails')}
</FormLabelDescription>
<Controller
rules={{ required: t('form.isOfficialFeedRequired') }}
control={control}
name='isOfficialFeed'
render={({ field }) => (
<>
<Select
{...field}
data-cy='isOfficialFeed'
sx={{ width: '200px' }}
>
<MenuItem value={'yes'}>{t('common:form.yes')}</MenuItem>
<MenuItem value={'no'}>{t('common:form.no')}</MenuItem>
<MenuItem value={'unsure'}>
{t('common:form.notSure')}
</MenuItem>
</Select>
<FormHelperText>
{errors.isOfficialFeed?.message ?? ''}
</FormHelperText>
</>
)}
/>
</FormControl>
</Grid>
<Grid item>
<FormControl component='fieldset'>
<FormLabel required>{t('dataType')}</FormLabel>
<Controller
rules={{ required: t('dataTypeRequired') }}
control={control}
name='dataType'
render={({ field }) => (
<Select {...field} data-cy='dataType'>
<Select {...field} data-cy='dataType' sx={{ width: '200px' }}>
<MenuItem value={'gtfs'}>
{t('common:gtfsSchedule')}
</MenuItem>
Expand Down
2 changes: 2 additions & 0 deletions web-app/src/app/screens/FeedSubmission/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type AuthTypes =

export interface FeedSubmissionFormFormInput {
isOfficialProducer: YesNoFormInput;
isOfficialFeed: 'yes' | 'no' | 'unsure' | undefined;
dataType: 'gtfs' | 'gtfs_rt';
transitProviderName: string;
feedLink?: string;
Expand Down Expand Up @@ -54,6 +55,7 @@ export interface FeedSubmissionFormFormInput {

const defaultFormValues: FeedSubmissionFormFormInput = {
isOfficialProducer: '',
isOfficialFeed: undefined,
dataType: 'gtfs',
transitProviderName: '',
feedLink: '',
Expand Down

0 comments on commit 0357784

Please sign in to comment.