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 all 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
68 changes: 49 additions & 19 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 @@ -26,13 +27,13 @@ Community chat: #organice on IRC [[https://libera.chat/][Libera.Chat]], or [[htt

organice is an implementation of [[http://orgmode.org/][Org mode]] without the dependency of
[[https://www.gnu.org/software/emacs/][Emacs]]. It is built for mobile and desktop browsers and syncs with
Dropbox, Google Drive and WebDAV.
[[https://www.dropbox.com/][Dropbox]], [[https://gitlab.com/][GitLab]], [[https://en.wikipedia.org/wiki/WebDAV][WebDAV]] and [[https://drive.google.com][Google Drive]].

At [[https://200ok.ch/][200ok]], we run an instance of organice at https://organice.200ok.ch,
which is open for anyone to use! organice does not have a back-end
(it's just a front-end application, which uses either Dropbox, Google
Drive or WebDAV as back-end storage). We don't store any kind of data
on our servers - we also don't use analytics on organice.200ok.ch.
(it's just a front-end application, which uses different back-end
storage providers). We don't store any kind of data on our servers -
we also don't use analytics on organice.200ok.ch.

[[https://raw.githubusercontent.com/200ok-ch/organice/master/images/screenshot-overview.png]]

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, GitLab, WebDAV or
Google Drive 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,22 +707,51 @@ 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
:END:

If you do not trust your data with Dropbox or Google, you are free to
host your own [[#webdav][WebDAV]] server and take any number of precautionary
measures. For example, you can encrypt your data on disk. organice
itself is just a front-end application, requires no server and has no
tracking system. Therefore, the data within any organice instance
(self hosted or not) is already only accessible to you, your browser
and the network between your browser and your chosen back-end.
Therefore, if have a strong SSL certificate configured on your WebDAV
server and organice instance, then organice will communicate securely
via HTTPS to your server where your data is as secure as you make it.
Then, your data will be encrypted and inaccessible to any third party.
use Gitlab ([[https://about.gitlab.com/solutions/open-source/][which is open-source]]) or host your own [[#webdav][WebDAV]] server and
take any number of precautionary measures.

For example, you can encrypt your data on disk. organice itself is
just a front-end application, requires no server and has no tracking
system. Therefore, the data within any organice instance (self hosted
or not) is already only accessible to you, your browser and the
network between your browser and your chosen back-end. Therefore, if
have a strong SSL certificate configured on your WebDAV server and
organice instance, then organice will communicate securely via HTTPS
to your server where your data is as secure as you make it. Then, your
data will be encrypted and inaccessible to any third party.

Of course, security is hard. So the above statement is not a
guarantee, but a guideline. You're responsible to ensure that the
Expand Down
4 changes: 4 additions & 0 deletions bin/compile_and_upload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ set -e
# Configure available back-end API keys
cp .env.sample .env
[ -z ${REACT_APP_DROPBOX_CLIENT_ID+x} ] || sed -i "s/your_dropbox_client_id/${REACT_APP_DROPBOX_CLIENT_ID}/" .env

[ -z ${REACT_APP_GOOGLE_DRIVE_API_KEY+x} ] || sed -i "s/your_google_drive_api_key/${REACT_APP_GOOGLE_DRIVE_API_KEY}/" .env
[ -z ${REACT_APP_GOOGLE_DRIVE_CLIENT_ID+x} ] || sed -i "s/your_google_drive_oauth_client_id/${REACT_APP_GOOGLE_DRIVE_CLIENT_ID}/" .env

[ -z ${REACT_APP_GITLAB_CLIENT_ID+x} ] || sed -i "s/your_gitlab_client_id/${REACT_APP_GITLAB_CLIENT_ID}/" .env
[ -z ${REACT_APP_GITLAB_SECRET+x} ] || sed -i "s/your_gitlab_secret/${REACT_APP_GITLAB_SECRET}/" .env

yarn install
yarn run build
cd build
Expand Down
5 changes: 5 additions & 0 deletions changelog.org
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ All user visible changes to organice will be documented in this file.

When there are updates to the changelog, you will be notified and see a 'gift' icon appear on the top right corner.

* [2021-11-01 Mon]
** Added
- *EPIC* Add GitLab as a sync back-end
- PR: https://github.com/200ok-ch/organice/pull/734
- Thank you [[https://github.com/chasecaleb][chasecaleb]] for the PR馃檹
* [2021-10-29 Fri]
** Fixed
- Loading settings when using WebDAV as synchronization back-end
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
6 changes: 3 additions & 3 deletions sample.org
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Give them a try on these nested headers to get a feel for how they operate:
***** Clooney
** Syncing
The "cloud" button in the lower left hand corner syncs changes to your
chosen sync service (Dropbox, Google Drive or WebDAV).
chosen sync service (Dropbox, GitLab, WebDAV or Google Drive).

If there's a newer version on the server and no local changes, it'll pull.

Expand Down Expand Up @@ -412,7 +412,7 @@ SCHEDULED: <2018-09-17 Mon>
** This entry also only shows on exactly one day
<2020-02-17 Mon>
* Syncing
organice pulls down your org files from Dropbox, Google Drive or WebDAV. Click the "Sign in" button in the upper right hand corner to sign in with either of them and authenticate organice.
organice pulls down your org files from Dropbox, GitLab, WebDAV or Google Drive. Click the "Sign in" button in the upper right hand corner to sign in with either of them and authenticate organice.

** Backups
The first time you push changes from organice back up to your chosen sync service, organice will make a backup of the original file first. It'll be named {your-file-name}.organice-bak. Dropbox and Google Drive also both keep a full version history of your files for you, but this is an additional precaution in case something goes wrong pushing the file back up.
Expand All @@ -430,7 +430,7 @@ Default behaviour:
You can adjust these defaults on a file per file basis by creating file settings in the [[/settings][settings menu]].

* organice operates completely client side
You don't log in to organice directly because organice doesn't have a back end - it operates completely client side using Dropbox, Google Drive or WebDAV as back-ends.
You don't log in to organice directly because organice doesn't have a back end - it operates completely client side using Dropbox, GitLab, WebDAV or Google Drive as back-ends for storage.
* Capture URL params and Siri support
organice supports a flexible mechanism for capturing using URL parameters. This mechanism integrates very nicely with the new [[https://support.apple.com/guide/shortcuts/welcome/ios][Siri Shortcuts]] feature in iOS 12, allowing you to use Siri to execute capture templates.

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