Commit b2724452 authored by Enrique Alcantara's avatar Enrique Alcantara

Load page source content service

Implements service that fetches a static site
page source using GitLab raw file API.

Implements a utility to access the raw file API
parent 328060f0
......@@ -47,6 +47,7 @@ const Api = {
adminStatisticsPath: '/api/:version/application/statistics',
pipelineSinglePath: '/api/:version/projects/:id/pipelines/:pipeline_id',
environmentsPath: '/api/:version/projects/:id/environments',
rawFilePath: '/api/:version/projects/:id/repository/files/:path/raw',
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
......@@ -497,6 +498,14 @@ const Api = {
return axios.get(url);
},
getRawFile(id, path, params = { ref: 'master' }) {
const url = Api.buildUrl(this.rawFilePath)
.replace(':id', encodeURIComponent(id))
.replace(':path', encodeURIComponent(path));
return axios.get(url, { params });
},
buildUrl(url) {
return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
},
......
import Api from '~/api';
const extractTitle = content => {
const matches = content.match(/title: (.+)\n/i);
return matches ? Array.from(matches)[1] : '';
};
const loadSourceContent = ({ projectId, sourcePath }) =>
Api.getRawFile(projectId, sourcePath).then(({ data }) => ({
title: extractTitle(data),
content: data,
}));
export default loadSourceContent;
......@@ -631,4 +631,32 @@ describe('Api', () => {
});
});
});
describe('getRawFile', () => {
const dummyProjectPath = 'gitlab-org/gitlab';
const dummyFilePath = 'doc/CONTRIBUTING.md';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${encodeURIComponent(
dummyProjectPath,
)}/repository/files/${encodeURIComponent(dummyFilePath)}/raw`;
describe('when the raw file is successfully fetched', () => {
it('resolves the Promise', () => {
mock.onGet(expectedUrl).replyOnce(200);
return Api.getRawFile(dummyProjectPath, dummyFilePath).then(() => {
expect(mock.history.get).toHaveLength(1);
});
});
});
describe('when an error occurs while getting a raw file', () => {
it('rejects the Promise', () => {
mock.onDelete(expectedUrl).replyOnce(500);
return Api.getRawFile(dummyProjectPath, dummyFilePath).catch(() => {
expect(mock.history.get).toHaveLength(1);
});
});
});
});
});
export const sourceContent = `
---
layout: handbook-page-toc
title: Handbook
twitter_image: '/images/tweets/handbook-gitlab.png'
---
## On this page
{:.no_toc .hidden-md .hidden-lg}
- TOC
{:toc .hidden-md .hidden-lg}
`;
export const sourceContentTitle = 'Handbook';
export const projectId = '123456';
export const sourcePath = 'foobar.md.html';
import Api from '~/api';
import loadSourceContent from '~/static_site_editor/services/load_source_content';
import { sourceContent, sourceContentTitle, projectId, sourcePath } from '../mock_data';
describe('loadSourceContent', () => {
describe('requesting source content succeeds', () => {
let result;
beforeEach(() => {
jest.spyOn(Api, 'getRawFile').mockResolvedValue({ data: sourceContent });
return loadSourceContent({ projectId, sourcePath }).then(_result => {
result = _result;
});
});
it('calls getRawFile API with project id and source path', () => {
expect(Api.getRawFile).toHaveBeenCalledWith(projectId, sourcePath);
});
it('extracts page title from source content', () => {
expect(result.title).toBe(sourceContentTitle);
});
it('returns raw content', () => {
expect(result.content).toBe(sourceContent);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment