Skip to content

Commit 6765eb5

Browse files
Merge pull request #408 from engaging-computing/dev
v2.0.0 | Goodbye Firebase
2 parents 43be737 + 94ae307 commit 6765eb5

23 files changed

Lines changed: 631 additions & 665 deletions

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#The client ID should NOT start with http or https! This will cause authentication failure!
2+
REACT_APP_GOOGLE_CLIENTID=<Required for authenticting with the backend, get this from a team member>

.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,8 @@
6262
"pragma": "React",
6363
"version": "16.8.4"
6464
}
65+
},
66+
"globals": {
67+
"process": "readonly"
6568
}
6669
}

.gitignore

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414

1515
# misc
1616
.DS_Store
17-
.env.local
18-
.env.development.local
19-
.env.test.local
20-
.env.production.local
17+
.env*
18+
!.env.example
2119

2220
npm-debug.log*
2321
yarn-debug.log*

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10.13

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ The Engaging Computing Group develops new technologies to enable learners—yout
99
## Status
1010
[![CircleCI](https://circleci.com/gh/engaging-computing/MYR.svg?style=shield)](https://circleci.com/gh/engaging-computing/MYR)
1111

12-
## Change Log - 1.9.0 -> 1.9.1
13-
- Fixed bug where key was hidden in some reference tabs.
14-
- setColor arguments are no longer case sensitive.
12+
## Change Log - 1.9.1 -> 2.0.0
13+
- Removed all Firebase dependencies and uses Mongo exclusively
14+
- Changed scene URL schema to be `/scene/:id`
15+
- Replaced authentication with Google OAuth2
1516

1617
## Acknowledgments
1718
MYR uses [Aframe](https://aframe.io), a fantastic open source project, to render objects and effects in the three dimensional space.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "myr",
3-
"version": "1.9.1",
3+
"version": "2.0.0",
44
"private": false,
55
"engines": {
66
"node": "10.13.0"
@@ -25,21 +25,22 @@
2525
"cannon": "^0.6.2",
2626
"create-react-app": "^3.0.1",
2727
"eslint": "5.6.0",
28-
"firebase": "^5.5.7",
2928
"jquery": "^3.3.1",
3029
"qrcode": "^1.2.0",
3130
"qrcode.react": "^0.8.0",
3231
"react": "^16.8.4",
3332
"react-ace": "^5.9.0",
3433
"react-color": "^2.17.0",
3534
"react-dom": "^16.2.0",
35+
"react-google-login": "^5.1.19",
3636
"react-progressive-image": "^0.3.0",
3737
"react-redux": "^5.0.7",
3838
"react-router-dom": "^4.2.2",
3939
"react-select": "^3.0.4",
4040
"reactour": "^1.9.1",
4141
"redux": "^3.7.2",
4242
"redux-thunk": "^2.3.0",
43+
"socket.io-client": "^2.3.0",
4344
"source-map-explorer": "^1.6.0",
4445
"styled-components": "^4.0.3",
4546
"three": "^0.98.0"

src/actions/collectionActions.js

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1-
import { collections, scenes } from "../firebase.js";
2-
31
import * as types from "../constants/ActionTypes";
42

3+
export const collectRef = "/apiv1/collections";
4+
55
export function asyncCollections(id) {
66
// fetch user's collections
77
return (dispatch) => {
88
if (id) {
99
let userCollections = [];
10-
collections.where("uid", "==", id).get().then(snap => {
11-
snap.forEach(doc => {
12-
let dat = doc.data();
13-
userCollections.push({
14-
id: doc.id,
15-
collectionID: dat.collectionID,
16-
data: dat
10+
fetch(collectRef, {headers: {"x-access-token": id}}).then((data) => {
11+
data.json().then((data) => {
12+
data.forEach((doc) => {
13+
userCollections.push(doc);
1714
});
1815
});
16+
dispatch(syncCollections(userCollections));
1917
});
20-
dispatch(syncCollections(userCollections));
2118
}
2219
};
2320
}
@@ -26,33 +23,40 @@ export function syncCollections(payload) {
2623
return { type: types.SYNC_CLASSES, payload: payload };
2724
}
2825

29-
export function asyncCollection(collectionID) {
26+
export function asyncCollection(collectionID, uid) {
3027
// fetch projects in collection
3128
return (dispatch) => {
3229
if (collectionID) {
3330
let collectionProjects = [];
3431
let projectOptions = [];
35-
scenes.where("settings.collectionID", "==", collectionID).get().then(snap => {
36-
snap.forEach(doc => {
37-
let dat = doc.data();
38-
collectionProjects.push({
39-
id: doc.id,
40-
name: dat.name,
41-
collectionID: dat.collectionID,
42-
data: dat
43-
});
32+
fetch(`${collectRef}/collectionID/${collectionID}`, {headers: {"x-access-token": uid}})
33+
.then((resp) => {
34+
switch(resp.status){
35+
case 200:
36+
resp.json().then((data) => {
37+
data.forEach((doc) => {
38+
collectionProjects.push(doc);
39+
});
40+
collectionProjects.map((proj) => {
41+
return projectOptions.push({
42+
value: proj._id,
43+
label: proj.name
44+
});
45+
});
46+
47+
dispatch(syncCollection(projectOptions));
48+
});
49+
break;
50+
case 401:
51+
window.alert("Error: You are not logged in as the owner of this collection");
52+
break;
53+
case 404:
54+
window.location.assign("/error-404");
55+
break;
56+
default:
57+
window.alert(`Error fetching collection scenes: ${resp.statusText}`);
58+
}
4459
});
45-
}).then(() => {
46-
collectionProjects.map((proj) =>
47-
projectOptions.push({
48-
value: proj.id,
49-
label: proj.name
50-
})
51-
);
52-
}).then(() => {
53-
dispatch(syncCollection(projectOptions));
54-
});
55-
5660
}
5761
};
5862
}
@@ -61,15 +65,45 @@ export function syncCollection(payload) {
6165
return { type: types.SYNC_CLASS, payload: payload };
6266
}
6367

64-
export function deleteCollection(id, name = null) {
65-
if (window.confirm(`Are you sure you want to delete collection "${name !== null ? name : id}"?`)) {
68+
export function deleteCollection(id, name = null, uid) {
69+
return (dispatch) => {
70+
name = (name ? name : id);
71+
if (window.confirm(`Are you sure you want to delete collection "${name}"?`)) {
6672

67-
// Delete Document
68-
collections.doc(id).delete()
69-
.catch((error) => {
70-
console.error("Error removing collection: ", error);
73+
// Delete Document
74+
fetch(`${collectRef}/collectionID/${name}`, {method: "DELETE", headers: { "x-access-token": uid}}).then((resp) => {
75+
if(resp.status !== 204) {
76+
console.error(`Error deleting collection ${name}: ${resp.statusText}`);
77+
return;
78+
}
79+
dispatch({ type: types.DELETE_CLASS, id: id });
7180
});
72-
return { type: types.DELETE_CLASS, id: id };
81+
}
82+
};
83+
}
84+
/**
85+
*
86+
* @param {string} name The name of the collection to be created
87+
* @param {*} uid A JWT token to authenticate with the backend
88+
*/
89+
export async function createCollection(name, uid) {
90+
name = name.toLowerCase().trim();
91+
92+
let resp = await fetch(`${collectRef}/`, {
93+
method: "POST",
94+
body: JSON.stringify({collectID: name}),
95+
headers:{"Content-Type": "application/json", "x-access-token": uid}
96+
});
97+
if(resp.status === 409){
98+
window.alert("Error: A collection already exists with that collection name.");
99+
return false;
100+
}else if (resp.status !== 201) {
101+
window.alert(`Error creating collection: ${resp.statusText}`);
102+
return false;
103+
}else{
104+
asyncCollections(uid);
105+
window.alert("Collection added!");
106+
return true;
73107
}
74108
}
75109

@@ -79,5 +113,7 @@ export default {
79113
asyncCollections,
80114
deleteCollection,
81115
syncCollection,
82-
syncCollections
116+
syncCollections,
117+
createCollection,
118+
collectRef
83119
};

src/actions/editorActions.js

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { scenes } from "../firebase.js";
21
import { loadScene } from "./sceneActions";
32
import { DEF_SETTINGS } from "../reducers/scene";
43
import * as types from "../constants/ActionTypes";
54

5+
const sceneRef = "/apiv1/scenes";
6+
67
/**
78
* @function - Sends a signal to the reducer to render the scene
89
*
@@ -41,41 +42,41 @@ export function recover() {
4142
*/
4243
export function fetchScene(id, uid = "anon") {
4344
return (dispatch) => { // Return a func that dispatches events after async
44-
scenes.doc(id).get().then((scene) => {
45-
let data = scene.data();
46-
if (data && data.pw) {
47-
let pw = prompt("Please enter the PW");
48-
if (pw !== data.pw) { return; }
45+
fetch(`${sceneRef}/id/${id}`, {redirect: "follow"}).then((response) =>{
46+
if(response.redirected && id !== "error-404"){
47+
let url = response.url.split("/");
48+
window.location.assign(`${window.origin}/scene/${url[url.length - 1]}?redirected=true`);
49+
return;
4950
}
50-
if (data && data.code) { // If it worked
51-
// render the editor
52-
dispatch(render(data.code, uid || "anon"));
53-
dispatch(updateSavedText(data.code));
54-
// Use default for eventual consistency in db
55-
let settings = DEF_SETTINGS;
5651

57-
// if the incoming scene has a settings, merge default with incoming
58-
if (data.settings) {
59-
settings = { ...settings, ...data.settings };
52+
if(response.status !== 200){
53+
if(response.status === 404){
54+
window.location.assign(window.origin + "/error-404");
55+
}else{
56+
console.error("Error retrieving scene. Reason: ", response.statusText);
6057
}
58+
return;
59+
}
6160

62-
// apply name/desc
63-
dispatch(loadScene({
64-
name: data.name ? data.name : "",
65-
id: data.uid === uid ? id : 0,
66-
ts: data.ts ? data.ts : Date.now(),
67-
desc: data.desc ? data.desc : "",
68-
settings: settings
69-
}));
70-
// apply settings, set id to 0 if not the owner of the scene
71-
// dispatch(loadSettings(settings));
61+
response.json().then((json) =>{
62+
if(json.code){
63+
dispatch(render(json.code, uid || "anon"));
64+
dispatch(updateSavedText(json.code));
65+
let settings = DEF_SETTINGS;
7266

73-
} else { // If no scene is found and we are not looking for 404 return 404
74-
if (id !== "error-404") {
75-
window.location.href = window.origin + "/error-404";
67+
if(json.settings){
68+
settings = {...settings, ...json.settings};
69+
}
70+
71+
dispatch(loadScene({
72+
name: json.name ? json.name : "",
73+
id: json.uid === uid ? id : 0,
74+
ts: json.updateTime ? json.updateTime : Date.now(),
75+
desc: json.desc ? json.desc : "",
76+
settings: settings
77+
}));
7678
}
77-
console.error("Unable to fetch scene:" + id);
78-
}
79+
});
7980
});
8081
};
8182
}

0 commit comments

Comments
 (0)