(fix #8) Add better error message for 403 protected projects with integration test and support.

This commit is contained in:
Winston Li 2015-02-20 12:38:12 +00:00
parent d9f5644b7b
commit ac50c26aef
10 changed files with 291 additions and 19 deletions

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.bridge;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
@ -19,7 +20,7 @@ public interface WriteLatexDataSource {
void unlockForProject(String projectName);
/* Called by request thread. */
public boolean repositoryExists(String projectName) throws FailedConnectionException;
public boolean repositoryExists(String projectName) throws ServiceMayNotContinueException;
public List<WritableRepositoryContents> getWritableRepositories(String projectName) throws FailedConnectionException, InvalidProjectException;
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException;

View file

@ -41,7 +41,6 @@ public class WLRepositoryResolver implements RepositoryResolver<HttpServletReque
cannot occur
*/
} catch (ServiceMayNotContinueException e) { /* Such as FailedConnectionException */
Util.printStackTrace(e);
throw e;
} catch (RuntimeException e) {
Util.printStackTrace(e);

View file

@ -41,7 +41,7 @@ public class SnapshotAPIState {
public SnapshotAPIState() {
getDoc = new HashMap<String, SnapshotGetDocResult>();
getDoc.put("1826rqgsdb", new SnapshotGetDocResult(243, "2014-11-30T18:40:58Z", "jdleesmiller+1@gmail.com", "John+1"));
getDoc.put("1826rqgsdb", new SnapshotGetDocResult(null, 243, "2014-11-30T18:40:58Z", "jdleesmiller+1@gmail.com", "John+1"));
getSavedVers = new HashMap<String, SnapshotGetSavedVersResult>();
List<SnapshotInfo> savedVers = new LinkedList<SnapshotInfo>();

View file

@ -59,7 +59,8 @@ public class SnapshotAPIStateBuilder {
private void addGetDocForProject(String projectName, JsonObject jsonGetDoc) {
getDoc.put(projectName,
new SnapshotGetDocResult(jsonGetDoc.get("versionID").getAsInt(),
new SnapshotGetDocResult(jsonGetDoc.get("error"),
jsonGetDoc.get("versionID").getAsInt(),
jsonGetDoc.get("createdAt").getAsString(),
jsonGetDoc.get("email").getAsString(),
jsonGetDoc.get("name").getAsString()));

View file

@ -10,6 +10,7 @@ import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotGetForV
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotGetForVersionResult;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotGetSavedVersRequest;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotInfo;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
import uk.ac.ic.wlgitbridge.writelatex.model.Snapshot;
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
@ -93,7 +94,12 @@ public class SnapshotFetcher implements PersistentStoreSource {
private int putLatestDoc(SnapshotGetDocRequest getDoc, Set<Integer> fetchedIDs, Map<Integer, SnapshotInfo> fetchedSnapshotInfos) throws FailedConnectionException, InvalidProjectException {
SnapshotGetDocResult result = getDoc.getResult();
int latestVersionID = result.getVersionID();
int latestVersionID = 0;
try {
latestVersionID = result.getVersionID();
} catch (SnapshotPostException e) {
throw new RuntimeException(e);
}
putFetchedResult(new SnapshotInfo(latestVersionID, result.getCreatedAt(), result.getName(), result.getEmail()), fetchedIDs, fetchedSnapshotInfos);
return latestVersionID;
}

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.writelatex;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
@ -43,7 +44,7 @@ public class WriteLatexAPI implements WriteLatexDataSource {
}
@Override
public boolean repositoryExists(String projectName) throws FailedConnectionException {
public boolean repositoryExists(String projectName) throws ServiceMayNotContinueException {
lockForProject(projectName);
SnapshotGetDocRequest snapshotGetDocRequest = new SnapshotGetDocRequest(projectName);
snapshotGetDocRequest.request();
@ -53,6 +54,8 @@ public class WriteLatexAPI implements WriteLatexDataSource {
return false;
} catch (FailedConnectionException e) {
throw e;
} catch (SnapshotPostException e) {
throw new ServiceMayNotContinueException(e.getMessage());
} finally {
unlockForProject(projectName);
}

View file

@ -6,24 +6,32 @@ import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Request;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Result;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.ProtectedProjectException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
/**
* Created by Winston on 06/11/14.
*/
public class SnapshotGetDocResult extends Result {
private int error;
private int versionID;
private String createdAt;
private String name;
private String email;
private InvalidProjectException invalidProjectException;
private SnapshotPostException exception;
public SnapshotGetDocResult(Request request, JsonElement json) throws FailedConnectionException {
super(request, json);
}
public SnapshotGetDocResult(int versionID, String createdAt, String email, String name) {
public SnapshotGetDocResult(JsonElement error, int versionID, String createdAt, String email, String name) {
if (error == null) {
this.error = -1;
} else {
this.error = error.getAsInt();
}
this.versionID = versionID;
this.createdAt = createdAt;
this.name = name;
@ -33,20 +41,40 @@ public class SnapshotGetDocResult extends Result {
@Override
public JsonElement toJson() {
JsonObject jsonThis = new JsonObject();
jsonThis.addProperty("latestVerId", versionID);
jsonThis.addProperty("latestVerAt", createdAt);
JsonObject latestVerBy = new JsonObject();
latestVerBy.addProperty("email", email);
latestVerBy.addProperty("name", name);
jsonThis.add("latestVerBy", latestVerBy);
if (error == -1) {
jsonThis.addProperty("latestVerId", versionID);
jsonThis.addProperty("latestVerAt", createdAt);
JsonObject latestVerBy = new JsonObject();
latestVerBy.addProperty("email", email);
latestVerBy.addProperty("name", name);
jsonThis.add("latestVerBy", latestVerBy);
} else {
jsonThis.addProperty("status", error);
String message;
if (error == 403) {
message = "Forbidden";
} else {
message = "Not Found";
}
jsonThis.addProperty("message", message);
}
return jsonThis;
}
@Override
public void fromJSON(JsonElement json) {
JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("status") && jsonObject.get("status").getAsInt() == 404) {
invalidProjectException = new InvalidProjectException();
if (jsonObject.has("status")) {
switch (jsonObject.get("status").getAsInt()) {
case 403:
exception = new ProtectedProjectException();
break;
case 404:
exception = new InvalidProjectException();
break;
default:
throw new IllegalArgumentException("unknown get doc error code");
}
} else {
versionID = jsonObject.get("latestVerId").getAsInt();
createdAt = jsonObject.get("latestVerAt").getAsString();
@ -62,9 +90,9 @@ public class SnapshotGetDocResult extends Result {
}
}
public int getVersionID() throws InvalidProjectException {
if (invalidProjectException != null) {
throw invalidProjectException;
public int getVersionID() throws SnapshotPostException {
if (exception != null) {
throw exception;
}
return versionID;
}

View file

@ -0,0 +1,29 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
import java.util.Arrays;
import java.util.List;
/**
* Created by Winston on 20/02/15.
*/
public class ProtectedProjectException extends SnapshotPostException {
@Override
public String getMessage() {
return "Your project is protected, and can't be cloned (yet).";
}
@Override
public List<String> getDescriptionLines() {
return Arrays.asList("You can't currently clone a protected project.");
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -2,6 +2,7 @@ package uk.ac.ic.wlgitbridge;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.TransportException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@ -17,7 +18,9 @@ import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Created by Winston on 11/01/15.
@ -40,6 +43,9 @@ public class WLGitBridgeIntegrationTest {
put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedTexFile/base/state.json")).build());
put("withDeletedTexFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedTexFile/withDeletedTexFile/state.json")).build());
}});
put("cannotCloneAProtectedProject", new HashMap<String, SnapshotAPIState>() {{
put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/cannotCloneAProtectedProject/state/state.json")).build());
}});
}};
@Rule
@ -138,6 +144,32 @@ public class WLGitBridgeIntegrationTest {
assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullADeletedTexFile/withDeletedTexFile/testproj"), git.toPath()));
}
@Test
public void cannotCloneAProtectedProject() throws IOException, GitAPIException {
MockSnapshotServer server = new MockSnapshotServer(3861, getResource("/cannotCloneAProtectedProject").toFile());
server.start();
server.setState(states.get("cannotCloneAProtectedProject").get("state"));
WLGitBridgeApplication wlgb = new WLGitBridgeApplication(new String[] {
makeConfigFile(33861, 3861)
});
wlgb.run();
folder.create();
File git = folder.newFolder();
try {
Git.cloneRepository()
.setURI("http://127.0.0.1:33861/protected.git")
.setDirectory(git)
.call()
.close();
} catch (TransportException e) {
assertEquals("http://127.0.0.1:33861/protected.git: Your project is protected, and can't be cloned (yet).", e.getMessage());
return;
} finally {
wlgb.stop();
}
fail();
}
private String makeConfigFile(int port, int apiPort) throws IOException {
File wlgb = folder.newFolder();
File config = folder.newFile();

View file

@ -0,0 +1,173 @@
[
{
"project": "protected",
"getDoc": {
"error": 403,
"versionID": 1,
"createdAt": "2014-11-30T18:40:58Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "contentchanged\n",
"path": "main.tex"
},
{
"content": "This text is from another file.",
"path": "foo/bar/test.tex"
}
],
"atts": []
}
],
"push": "success",
"postback": {
"type": "outOfDate"
}
},
{
"project": "invalidFiles",
"getDoc": {
"versionID": 1,
"createdAt": "2014-11-30T18:40:58Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "changedñcontent\n",
"path": "main.tex"
},
{
"content": "This text is from another file.",
"path": "foo/bar/test.tex"
}
],
"atts": []
}
],
"push": "success",
"postback": {
"type": "invalidFiles",
"errors": [
{
"file": "file.invalid",
"state": "error"
},
{
"file": "virus.exe",
"state": "disallowed"
},
{
"file": "my image.jpg",
"state": "unclean_name",
"cleanFile": "my_image.jpg"
}
]
}
},
{
"project": "invalidProject",
"getDoc": {
"versionID": 1,
"createdAt": "2014-11-30T18:40:58Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "content\n",
"path": "main.tex"
},
{
"content": "This text is from another file.",
"path": "foo/bar/test.tex"
}
],
"atts": []
}
],
"push": "success",
"postback": {
"type": "invalidProject",
"errors": [
"No main.tex file exists."
]
}
},
{
"project": "error",
"getDoc": {
"versionID": 1,
"createdAt": "2014-11-30T18:40:58Z",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1"
},
"getSavedVers": [
{
"versionID": 1,
"comment": "added more info on doc GET and error details",
"email": "jdleesmiller+1@gmail.com",
"name": "John+1",
"createdAt": "2014-11-30T18:47:01Z"
}
],
"getForVers": [
{
"versionID": 1,
"srcs": [
{
"content": "content\n",
"path": "main.tex"
},
{
"content": "This text is from another file.",
"path": "foo/bar/test.tex"
}
],
"atts": []
}
],
"push": "success",
"postback": {
"type": "error"
}
}
]