diff --git a/Dockerfile b/Dockerfile index 506e4b2..d9568bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,5 @@ EXPOSE 3000 COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/.next ./.next COPY --from=builder /app/postgraphile.tags.json5 ./postgraphile.tags.json5 -RUN npx next telemetry disable CMD ["node_modules/.bin/next", "start"] diff --git a/README.md b/README.md index b31375a..68ef7e1 100644 --- a/README.md +++ b/README.md @@ -58,13 +58,15 @@ Contributions for the following are very welcome. - [x] Number: Usage Total Count - [x] Graph: Usage of last 31 days - [ ] Link Ownership -- [ ] Link Parameters +- [x] Link Parameters + - For example, a `gh` alias with url `https://github.com/$1/$2` allows `https://go/gh/armand1m/golinks` to be possible. - [ ] Link Groups (Folders) - [x] URL: Accept `/` and can be redirected - [ ] UI: Folds URL groups - [ ] Private Links - [ ] Temporary Links - [ ] Random Alias +- [ ] Help section - [ ] Chrome Plugin ## Usage diff --git a/lib/features/link-parameters/index.ts b/lib/features/link-parameters/index.ts new file mode 100644 index 0000000..ac3ce2b --- /dev/null +++ b/lib/features/link-parameters/index.ts @@ -0,0 +1,74 @@ +import { ApolloClient, NormalizedCacheObject } from '@apollo/client'; +import { + GetLinkByAliasDocument, + GetLinkByAliasQuery, + GetLinkByAliasQueryVariables, +} from '../../queries/getLinkByAlias.graphql'; + +interface CreateRedirectUrlProps { + linkUrl: string; + linkAlias: string; + contextAlias: string[]; +} + +export const createRedirectUrl = ({ + linkUrl, + linkAlias, + contextAlias, +}: CreateRedirectUrlProps) => { + const urlParameters = linkUrl.match(/\$(\d+)/g); + + if (urlParameters?.length) { + const parameters = contextAlias.filter( + (param) => param !== linkAlias && !linkAlias.includes(param) + ); + + const finalUrl = urlParameters.reduce((acc, urlParam, index) => { + return acc.replace(urlParam, parameters[index]); + }, linkUrl); + + return finalUrl; + } + + return linkUrl; +}; + +interface FindLinkRecursiveProps { + contextAlias: string[]; + apolloClient: ApolloClient; +} + +export const findLinkRecursive = async ({ + contextAlias, + apolloClient, +}: FindLinkRecursiveProps): Promise< + GetLinkByAliasQuery['linkByAlias'] +> => { + if (contextAlias.length === 0) { + return undefined; + } + + const alias = contextAlias.join('/'); + + const queryResult = await apolloClient.query< + GetLinkByAliasQuery, + GetLinkByAliasQueryVariables + >({ + query: GetLinkByAliasDocument, + variables: { + alias, + }, + }); + + const link = queryResult.data.linkByAlias; + + if (!link) { + const $contextAlias = contextAlias.slice(0, -1); + return findLinkRecursive({ + contextAlias: $contextAlias, + apolloClient, + }); + } + + return link; +}; diff --git a/pages/[...alias].tsx b/pages/[...alias].tsx index 93ddeeb..f2619a7 100644 --- a/pages/[...alias].tsx +++ b/pages/[...alias].tsx @@ -12,11 +12,6 @@ import { import { NotFoundAnimation } from '../components/NotFoundAnimation'; import { TopNavigation } from '../components/TopNavigation'; -import { - GetLinkByAliasDocument, - GetLinkByAliasQuery, - GetLinkByAliasQueryVariables, -} from '../lib/queries/getLinkByAlias.graphql'; import { CreateLinkUsageMetricDocument, CreateLinkUsageMetricMutation, @@ -27,6 +22,10 @@ import { SearchLinksQuery, SearchLinksQueryVariables, } from '../lib/queries/searchLinks.graphql'; +import { + createRedirectUrl, + findLinkRecursive, +} from '../lib/features/link-parameters'; interface Props { alias: string; @@ -133,8 +132,6 @@ export const getServerSideProps: GetServerSideProps = async ( context?.req as NextApiRequest ); const apolloClient = initializeApollo(); - - const alias = (context.query.alias as string[]).join('/'); const logoname = Config.metadata.logoname; const baseUrl = Config.metadata.baseUrl; const isAuthEnabled = Config.features.auth0; @@ -148,19 +145,14 @@ export const getServerSideProps: GetServerSideProps = async ( ) : false; - const queryResult = await apolloClient.query< - GetLinkByAliasQuery, - GetLinkByAliasQueryVariables - >({ - query: GetLinkByAliasDocument, - variables: { - alias, - }, + const contextAlias = context.query.alias as string[]; + const link = await findLinkRecursive({ + contextAlias, + apolloClient, }); - const link = queryResult.data.linkByAlias; - if (!link) { + const alias = contextAlias.join('/'); const searchResults = await apolloClient.query< SearchLinksQuery, SearchLinksQueryVariables @@ -187,7 +179,7 @@ export const getServerSideProps: GetServerSideProps = async ( } /** - * Trigger metric update and forget about it. + * Trigger metric update in the background. */ apolloClient .mutate< @@ -214,7 +206,11 @@ export const getServerSideProps: GetServerSideProps = async ( const response = context.res; response.writeHead(302, { - Location: link.url, + Location: createRedirectUrl({ + linkUrl: link.url, + linkAlias: link.alias, + contextAlias, + }), }); response.end(); @@ -225,7 +221,7 @@ export const getServerSideProps: GetServerSideProps = async ( **/ return { props: { - alias, + alias: link.alias, baseUrl, logoname, isMobile,