Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GitLab as a sync backend #734

Merged
merged 19 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from 14 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
4 changes: 3 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
REACT_APP_DROPBOX_CLIENT_ID=your_dropbox_client_id
REACT_APP_GOOGLE_DRIVE_API_KEY=your_google_drive_api_key
REACT_APP_GOOGLE_DRIVE_CLIENT_ID=your_google_drive_oauth_client_id
REACT_APP_GOOGLE_DRIVE_CLIENT_ID=your_google_drive_oauth_client_id
REACT_APP_GITLAB_CLIENT_ID=your_gitlab_client_id
REACT_APP_GITLAB_SECRET=your_gitlab_secret
chasecaleb marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tags
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/.log/

*~

Expand Down
38 changes: 33 additions & 5 deletions README.org
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# -*- org-adapt-indentation: nil; fill-column: 70; -*-
#+title: organice documentation

#+html: <h1 align="center">organice - /'蓴:g蓹na瑟z/</h1>
Expand Down Expand Up @@ -385,8 +386,8 @@ yarn install --production=false

*** Setup any of the synchronization back-ends

organice can sync your Org files using Dropbox, Google Drive and
WebDAV as back-ends.
organice can sync your Org files using Dropbox, Google Drive, GitLab,
and WebDAV as back-ends.

If you want to develop a feature that needs synchronization, then you
will have to set up any of those options. If you want to work on a
Expand All @@ -406,7 +407,7 @@ your files with either of them anyway and use WebDAV all the way.

In any case, [[#faq_webdav][here's how to get running locally with a WebDAV setup]].

**** Dropbox or Google Drive
**** Dropbox, Google Drive, or GitLab

To test against your own Dropbox or Google Drive application, you'll
need to create a ~.env~ file by copying [[file:.env.sample][.env.sample]] to just ~.env~.
Expand All @@ -415,8 +416,8 @@ need to create a ~.env~ file by copying [[file:.env.sample][.env.sample]] to jus
cp .env.sample .env
#+END_SRC

Then, fill in the blanks in ~.env~ with your Dropbox or Google Drive
credentials. More information about that is in the section
Then, fill in the blanks in ~.env~ with your Dropbox, Google Drive, or
GitLab credentials. More information about that is in the section
[[#synchronization_back_ends][Synchronization back-ends]].

**** Running the application
Expand Down Expand Up @@ -706,6 +707,33 @@ Client ID. Then, you will create a new ~.env~ file (analogous to
=REACT_APP_GOOGLE_DRIVE_API_KEY= and
=REACT_APP_GOOGLE_DRIVE_CLIENT_ID=.

*** GitLab
:PROPERTIES:
:CUSTOM_ID: gitlab
:END:

To configure your own instance of organice for GitLab, please create
an OAuth application by going to [[https://gitlab.com/-/profile/applications][GitLab's application settings for
your profile]] and filling out the form with the following details:

- Name: "organice test" (or whatever you prefer)
- Redirect URI: ~http://localhost:3000/~ for local development, or
whatever domain you are hosting it with.
- Confidential: /uncheck/ this
- Expire access tokens: leave checked
- Scopes: =api= only

Once filled out, click "save application" and keep this page open.
Then, create a new ~.env~ file (analogous to ~.env.sample~) and set
the following variables:

- =REACT_APP_GITLAB_CLIENT_ID=: The value that GitLab provides for
=Application ID=
- =REACT_APP_GITLAB_SECRET=: The value that GitLab provides for =Secret=.

You may also refer to [[https://docs.gitlab.com/ee/integration/oauth_provider.html#user-owned-applications][GitLab's documentation]] for more information
regarding OAuth applications, if interested.

*** Encryption
:PROPERTIES:
:CUSTOM_ID: encryption
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"node": "^12.13.1"
},
"dependencies": {
"@bity/oauth2-auth-code-pkce": "^2.13.0",
"bowser": "^2.11.0",
"classnames": "^2.2.6",
"date-fns": "^2.16.1",
Expand Down
39 changes: 39 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import { setDisappearingLoadingMessage, restoreStaticFile } from './actions/base
import createDropboxSyncBackendClient from './sync_backend_clients/dropbox_sync_backend_client';
import createGoogleDriveSyncBackendClient from './sync_backend_clients/google_drive_sync_backend_client';
import createWebDAVSyncBackendClient from './sync_backend_clients/webdav_sync_backend_client';
import createGitLabSyncBackendClient, {
createGitlabOAuth,
} from './sync_backend_clients/gitlab_sync_backend_client';

import './base.css';

Expand All @@ -37,6 +40,30 @@ import {
import _ from 'lodash';
import { Map } from 'immutable';

const handleGitLabAuthResponse = async (oauthClient) => {
let success = false;
try {
success = await oauthClient.isReturningFromAuthServer();
await oauthClient.getAccessToken();
} catch {
success = false;
}
if (!success) {
// Edge case: somehow OAuth success redirect occurred but there isn't a code in
// the current location's search params. This /shouldn't/ happen in practice.
alert('Unexpected sign in error, please try again');
return;
}

const syncClient = createGitLabSyncBackendClient(oauthClient);
const isAccessible = await syncClient.isProjectAccessible();
if (!isAccessible) {
alert('Failed to access GitLab project - is the URL is correct?');
} else {
window.location.search = '';
}
};

export default class App extends PureComponent {
constructor(props) {
super(props);
Expand Down Expand Up @@ -80,6 +107,18 @@ export default class App extends PureComponent {
client,
});
break;
case 'GitLab':
const gitlabOAuth = createGitlabOAuth();
if (gitlabOAuth.isAuthorized()) {
client = createGitLabSyncBackendClient(gitlabOAuth);
initialState.syncBackend = Map({
isAuthenticated: true,
client,
});
} else {
handleGitLabAuthResponse(gitlabOAuth);
}
break;
case 'WebDAV':
client = createWebDAVSyncBackendClient(
getPersistedField('webdavEndpoint'),
Expand Down
1 change: 1 addition & 0 deletions src/actions/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export const setShouldStoreSettingsInSyncBackend = (newShouldStoreSettingsInSync
const client = getState().syncBackend.get('client');
switch (client.type) {
case 'Dropbox':
case 'GitLab':
case 'WebDAV':
client
.deleteFile('/.organice-config.json')
Expand Down
8 changes: 8 additions & 0 deletions src/actions/sync_backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ActionCreators } from 'redux-undo';
import { setLoadingMessage, hideLoadingMessage, clearModalStack, setIsLoading } from './base';
import { parseFile, setDirty, setLastSyncAt, setOrgFileErrorMessage } from './org';
import { localStorageAvailable, persistField } from '../util/settings_persister';
import { createGitlabOAuth } from '../sync_backend_clients/gitlab_sync_backend_client';

import { addSeconds } from 'date-fns';

Expand All @@ -20,6 +21,10 @@ export const signOut = () => (dispatch, getState) => {
case 'Google Drive':
gapi.auth2.getAuthInstance().signOut();
break;
case 'GitLab':
persistField('gitLabProject', null);
createGitlabOAuth().reset();
break;
default:
}

Expand Down Expand Up @@ -97,6 +102,9 @@ export const pushBackup = (pathOrFileId, contents) => {
pathOrFileId = pathOrFileId.startsWith('/') ? pathOrFileId.substr(1) : pathOrFileId;
client.duplicateFile(pathOrFileId, (fileName) => `${fileName}.organice-bak`);
break;
case 'GitLab':
// No-op for GitLab, because the beauty of version control makes backup files redundant.
break;
munen marked this conversation as resolved.
Show resolved Hide resolved
default:
}
};
Expand Down
1 change: 1 addition & 0 deletions src/components/FileBrowser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const FileBrowser = ({
const getParentDirectoryPath = () => {
switch (syncBackendType) {
case 'Dropbox':
case 'GitLab':
case 'WebDAV':
const pathParts = path.split('/');
return pathParts.slice(0, pathParts.length - 1).join('/');
Expand Down
Loading