Code EOL. Docs genesis.

This commit is contained in:
gitpitch 2020-09-02 20:00:55 +01:00
parent e45b14eea0
commit 033fa5d1ac
1398 changed files with 10133 additions and 69905 deletions

View File

@ -5,7 +5,7 @@
### General Support
If you have general questions about GitPitch that are not answered by the [GitPitch How-To Wiki](https://github.com/gitpitch/gitpitch/wiki) then the best way to ask those questions is by [sending me a tweet](https://twitter.com/gitpitch) on Twitter. Otherwise [open a new issue](https://github.com/gitpitch/gitpitch/issues) on GitHub.
If you have general questions about GitPitch that are not answered by the [GitPitch Docs](https://docs.gitpitch.com) then the best way to ask those questions is by [sending me a tweet](https://twitter.com/gitpitch) on Twitter. Otherwise [open a new issue](https://github.com/gitpitch/gitpitch/issues) on GitHub.
### Bug Reports

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 David Russell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,76 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import com.gitpitch.factory.MarkdownModelFactory;
import com.gitpitch.git.*;
import com.gitpitch.git.vendors.*;
import com.gitpitch.models.Markdown;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.services.*;
import com.gitpitch.policies.CacheTimeout;
import com.gitpitch.policies.Dependencies;
import com.gitpitch.policies.Runtime;
import com.gitpitch.executors.FrontEndThreads;
import com.gitpitch.executors.BackEndThreads;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/*
* Guice DI injection dependencies for the GitPitch server.
*/
public class Module extends AbstractModule {
@Override
public void configure() {
bind(DiskService.class).asEagerSingleton();
bind(GitService.class).asEagerSingleton();
bind(PitchService.class).asEagerSingleton();
bind(PrintService.class).asEagerSingleton();
bind(OfflineService.class).asEagerSingleton();
bind(ShellService.class).asEagerSingleton();
bind(ImageService.class).asEagerSingleton();
bind(VideoService.class).asEagerSingleton();
bind(GISTService.class).asEagerSingleton();
bind(CodeService.class).asEagerSingleton();
bind(SlideService.class).asEagerSingleton();
bind(ShortcutsService.class).asEagerSingleton();
bind(WebService.class).asEagerSingleton();
bind(ComposableService.class).asEagerSingleton();
bind(GRSManager.class).asEagerSingleton();
bind(GitHub.class).asEagerSingleton();
bind(GitLab.class).asEagerSingleton();
bind(BitBucket.class).asEagerSingleton();
bind(Gitea.class).asEagerSingleton();
bind(Gogs.class).asEagerSingleton();
bind(GitBucket.class).asEagerSingleton();
bind(FrontEndThreads.class).asEagerSingleton();
bind(BackEndThreads.class).asEagerSingleton();
bind(Dependencies.class).asEagerSingleton();
bind(CacheTimeout.class).asEagerSingleton();
bind(Runtime.class).asEagerSingleton();
install(new FactoryModuleBuilder().implement(Markdown.class, MarkdownModel.class)
.build(MarkdownModelFactory.class));
}
}

View File

@ -1,515 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.controllers;
import com.gitpitch.git.GRS;
import com.gitpitch.git.GRSManager;
import com.gitpitch.models.GitRepoModel;
import com.gitpitch.models.Markdown;
import com.gitpitch.executors.FrontEndThreads;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.services.PitchService;
import com.gitpitch.oembed.PitchEmbed;
import com.gitpitch.policies.Dependencies;
import com.gitpitch.policies.Runtime;
import com.gitpitch.utils.GitRepoRenderer;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.RFE;
import play.Logger;
import play.Logger.ALogger;
import play.libs.Json;
import play.libs.ws.*;
import play.mvc.*;
import views.html.*;
import javax.inject.*;
import java.io.File;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
/**
* Front controller for GitPitch service.
*/
public class PitchController extends Controller {
private final Logger.ALogger log = Logger.of(this.getClass());
private final PitchService pitchService;
private final FrontEndThreads frontEndThreads;
private final Dependencies deps;
private final Runtime runtime;
private final GRSManager grsManager;
@Inject
public PitchController(PitchService pitchService,
FrontEndThreads frontEndThreads,
Dependencies deps,
Runtime runtime,
GRSManager grsManager) {
this.pitchService = pitchService;
this.frontEndThreads = frontEndThreads;
this.deps = deps;
this.runtime = runtime;
this.grsManager = grsManager;
}
/*
* Catchall redirects any URL with a trailing slash to the
* URL minus the trailing slash. Any remaining unhandled URLs
* are redirected to the GitPitch website.
*/
public Result catchall(String path) {
try {
if (path != "/" && path.endsWith("/")) {
return redirect("/" + path.substring(0, path.length()-1));
} else {
return ok(com.gitpitch.views.html.NotFound.render());
}
} catch(Exception ex) {
return ok(com.gitpitch.views.html.NotFound.render());
}
}
/*
* Slideshow builds and renders a GitPitch presentation.
*/
public CompletionStage<Result> slideshow(String user,
String repo,
String branch,
String grs,
String theme,
String pitchme,
String notes,
String offline,
String fragments,
String webprint) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme, notes);
boolean isOffline =
(offline == null) ? false : Boolean.parseBoolean(offline);
boolean serverPrinting =
(fragments == null) ? false : !Boolean.parseBoolean(fragments);
boolean webPrinting =
(webprint == null) ? false : Boolean.parseBoolean(webprint);
Optional<GitRepoModel> grmo = pitchService.cachedRepo(pp);
Optional<SlideshowModel> ssmo = pitchService.cachedYAML(pp);
if (grmo.isPresent() && ssmo.isPresent()) {
if (isOffline)
log.info("slideshow: [ deps, cached, offlne ] {}", pp);
else
log.info("slideshow: [ deps, cached, online ] {}", pp);
GitRepoModel grm = grmo.get();
GitRepoRenderer rndr =
GitRepoRenderer.build(pp, grm, runtime, grsManager.listGRS());
SlideshowModel ssm = ssmo.get();
/*
* Clone cached SlideshowModel in order to adjust for any
* changes on the current PitchParams, such as {theme}.
*/
ssm = ssm.clone(pp);
return CompletableFuture.completedFuture(
ok(com.gitpitch.views.html.Slideshow.render(ssm, rndr, deps,
gaToken(), isOffline, serverPrinting, webPrinting)));
} else {
return CompletableFuture.supplyAsync(() -> {
return pitchService.fetchRepo(pp);
}, frontEndThreads.POOL)
.thenApply(repoFetched -> {
GitRepoRenderer rndr =
GitRepoRenderer.build(pp, repoFetched, runtime,
grsManager.listGRS());
if (ssmo.isPresent()) {
if (webPrinting)
log.info("slideshow: [ repo, fetchd, printg ] {}", pp);
else
if (isOffline)
log.info("slideshow: [ repo, fetchd, offlne ] {}", pp);
else
log.info("slideshow: [ repo, fetchd, online ] {}", pp);
SlideshowModel ssm = ssmo.get();
/*
* Clone cached SlideshowModel in order to adjust for any
* changes on the current PitchParams, such as {theme}.
*/
ssm = ssm.clone(pp);
return ok(com.gitpitch.views.html.Slideshow.render(ssm,
rndr, deps, gaToken(),
isOffline, serverPrinting, webPrinting));
} else {
SlideshowModel ssm = pitchService.fetchYAML(pp);
if (webPrinting)
log.info("slideshow: [ yaml, fetchd, printg ] {}", pp);
else
if (isOffline)
log.info("slideshow: [ yaml, fetchd, offlne ] {}", pp);
else
log.info("slideshow: [ yaml, fetchd, online ] {}", pp);
return ok(com.gitpitch.views.html.Slideshow.render(ssm,
rndr, deps, gaToken(),
isOffline, serverPrinting, webPrinting));
}
});
}
} // slideshow action
/*
* Markdown processes and renders PITCHME.md markdown.
*/
public CompletionStage<Result> markdown(String grs,
String user,
String repo,
String branch,
String pitchme) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, null, pitchme);
Optional<Markdown> mdmo = pitchService.cachedMarkdown(pp);
if (mdmo.isPresent()) {
Markdown mdm = mdmo.get();
log.info("markdown: [ mdwn, cached, online ] {}", pp);
return CompletableFuture.completedFuture(ok(mdm.produce())
.as("text/markdown"));
} else {
return CompletableFuture.supplyAsync(() -> {
return pitchService.fetchMarkdown(pp);
}, frontEndThreads.POOL)
.thenApply(fetched -> {
if (fetched != null) {
log.info("markdown: [ mdwn, fetchd, online ] {}", pp);
return ok(fetched.produce()).as("text/markdown");
}
if (pp.isMaster()) {
log.info("markdown: [ mdwn, notfnd, online ] {}", pp);
return ok(RFE.master(pp, grsManager.get(pp)))
.as("text/markdown");
} else {
log.info("markdown: [ mdwn, notfnd, online ] {}", pp);
return ok(RFE.branch(pp, grsManager.get(pp)))
.as("text/markdown");
}
});
}
} // markdown action
/*
* Home generates presentation home side-panel.
*/
public CompletionStage<Result> home(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String offline) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme);
boolean isOffline =
(offline == null) ? false : Boolean.parseBoolean(offline);
Optional<GitRepoModel> grmo = pitchService.cachedRepo(pp);
GitRepoModel grm = grmo.orElse(null);
GitRepoRenderer rndr =
GitRepoRenderer.build(pp, grm, runtime, grsManager.listGRS());
return CompletableFuture.completedFuture(
ok(com.gitpitch.views.html.Home.render(rndr,
deps,
isOffline,
userAgentIsChrome())));
} // home action
/*
* Git generates presentation git (grs) side-panel.
*/
public CompletionStage<Result> git(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String offline) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme);
boolean isOffline =
(offline == null) ? false : Boolean.parseBoolean(offline);
Optional<GitRepoModel> grmo = pitchService.cachedRepo(pp);
GitRepoModel grm = grmo.orElse(null);
GitRepoRenderer rndr =
GitRepoRenderer.build(pp, grm, runtime, grsManager.listGRS());
return CompletableFuture.completedFuture(
ok(com.gitpitch.views.html.Git.render(rndr, deps, isOffline)));
} // git action
/*
* Themes generates presentation themes side-panel.
*/
public CompletionStage<Result> themes(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String offline) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme);
boolean isOffline =
(offline == null) ? false : Boolean.parseBoolean(offline);
Optional<GitRepoModel> grmo = pitchService.cachedRepo(pp);
Optional<SlideshowModel> ssmo = pitchService.cachedYAML(pp);
GitRepoModel grm = grmo.orElse(null);
GitRepoRenderer rndr =
GitRepoRenderer.build(pp, grm, runtime, grsManager.listGRS());
String fixedTheme = null;
if(ssmo.isPresent()) {
fixedTheme = ssmo.get().fixedTheme() ? ssmo.get().fetchTheme() : null;
}
return CompletableFuture.completedFuture(
ok(com.gitpitch.views.html.Themes.render(rndr, deps, fixedTheme, isOffline)));
} // themes action
/*
* Print generates and renders PITCHME.pdf.
*/
public CompletionStage<Result> print(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String notes) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme, notes);
Optional<File> pdfo = pitchService.cachedPDF(pp);
if (pdfo.isPresent()) {
log.info("print: [ cached, printg ] {}", pp);
File pdf = pdfo.get();
return CompletableFuture.completedFuture(ok(pdf)
.as("application/pdf"));
} else {
return CompletableFuture.supplyAsync(() -> {
return pitchService.fetchPDF(pp);
}, frontEndThreads.POOL)
.thenApply(fetched -> {
if (fetched != null) {
log.info("print: [ fetchd, printg ] {}", pp);
return ok(fetched).as("application/pdf");
} else {
log.info("print: [ failed, printg ] {}", pp);
return ok(PITCHME_PRINT_ERROR);
}
});
}
} // print action
/*
* Offline generates and renders PITCHME.zip.
*/
public CompletionStage<Result> offline(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String notes) {
PitchParams pp =
PitchParams.build(grsOnCall(grs),
user, repo, branch, theme, pitchme, notes);
log.debug("offline: pp={}", pp);
Optional<File> zipo = pitchService.cachedZip(pp);
if (zipo.isPresent()) {
log.info("offline: [ cached, downld ] {}", pp);
File zip = zipo.get();
return CompletableFuture.completedFuture(ok(zip)
.as("application/zip"));
} else {
return CompletableFuture.supplyAsync(() -> {
return pitchService.fetchZip(pp);
}, frontEndThreads.POOL)
.thenApply(fetched -> {
if (fetched != null) {
log.info("offline: [ fetchd, downld ] {}", pp);
return ok(fetched).as("application/zip");
} else {
log.info("offline: [ failed, downld ] {}", pp);
return ok(PITCHME_OFFLINE_ERROR);
}
});
}
} // offline action
/*
* Gist generates and renders GitHub-Gist HTML for
* embedding within slideshows.
*/
public Result gist(String gid) {
return ok(com.gitpitch.views.html.Gist.render(gid, deps));
} // gist action
/*
* oembed generates an oEmbed provider response.
*/
public Result oembed(String url,
String format,
String width,
String height,
String maxwidth,
String maxheight,
String referrer) {
log.info("oembed: [ {}, {}, {} ]", url, format, referrer);
PitchEmbed pembed = PitchEmbed.build(grsManager,
url,
width,
height,
maxwidth,
maxheight);
Result result = TODO; // Indicates 501 NotImplemented
switch(format) {
case OEMBED_JSON:
result = ok(Json.toJson(pembed));
break;
case OEMBED_XML:
result = ok(com.gitpitch.views.xml.OEmbed.render(pembed));
break;
}
return result;
} // oembed action
public Result template(String template) {
String target = (template != null) ? template : TEMPLATE_UNDEF;
String targetArchive = TEMPLATE_REPO + target + TEMPLATE_ZIP;
log.info("template: downloading {}", target);
return redirect(targetArchive);
}
/*
* Determine GRS on call, explicitly defined or default.
*/
private String grsOnCall(String grsParam) {
return grsManager.getType(grsParam);
}
private boolean userAgentIsChrome() {
boolean isChrome = false;
try {
String[] userAgentHeaders =
request().headers().get(Http.HeaderNames.USER_AGENT);
if(userAgentHeaders.length > 0) {
String userAgent = userAgentHeaders[0];
isChrome = userAgent.contains("Chrome/") ||
userAgent.contains("Chromium/");
}
} catch(Exception ex) {}
return isChrome;
}
private String gaToken() {
return runtime.config("gitpitch.google.analytics.token");
}
private static final String PITCHME_PRINT_ERROR =
"GitPitch Slideshow print service temporarily unavailable.";
private static final String PITCHME_OFFLINE_ERROR =
"GitPitch Slideshow offline service temporarily unavailable.";
private static final String OEMBED_JSON = "json";
private static final String OEMBED_XML = "xml";
private static final String TEMPLATE_REPO =
"https://github.com/gitpitch/templates/archive/";
private static final String TEMPLATE_ZIP = ".zip";
private static final String TEMPLATE_UNDEF = "UNDEFINED";
}

View File

@ -1,52 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.executors;
import play.inject.ApplicationLifecycle;
import javax.inject.*;
import java.util.concurrent.CompletableFuture;
/*
* Server thread pool for backend async operations.
*/
@Singleton
public final class BackEndThreads extends BaseThreadPool {
@Inject
public BackEndThreads(ApplicationLifecycle lifecycle) {
super("Back-End-Pool", 50, lifecycle);
lifecycle.addStopHook(() -> {
try {
POOL.shutdownNow();
} catch (SecurityException ex) {
}
return CompletableFuture.completedFuture(null);
});
}
}

View File

@ -1,75 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.executors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import play.Logger;
import play.Logger.ALogger;
import play.inject.ApplicationLifecycle;
import javax.inject.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/*
* Server thread pool for async operations.
*/
public abstract class BaseThreadPool {
private final Logger.ALogger log = Logger.of(this.getClass());
public final ExecutorService POOL;
private final String poolName;
private final int poolSize;
private final ApplicationLifecycle lifecycle;
protected BaseThreadPool(String poolName,
int poolSize,
ApplicationLifecycle lifecycle) {
this.poolName = poolName;
this.poolSize = poolSize;
this.lifecycle = lifecycle;
ThreadFactory namedTF =
new ThreadFactoryBuilder().setNameFormat(poolName).build();
POOL = Executors.newFixedThreadPool(poolSize, namedTF);
lifecycle.addStopHook(() -> {
try {
POOL.shutdownNow();
} catch (SecurityException ex) {
log.warn("{}: thread pool shutdown ex={}", ex);
} finally {
log.info("{}: thread pool shutdown.", poolName);
}
return CompletableFuture.completedFuture(null);
});
}
}

View File

@ -1,52 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.executors;
import play.inject.ApplicationLifecycle;
import javax.inject.*;
import java.util.concurrent.CompletableFuture;
/*
* Server thread pool for frontend async operations.
*/
@Singleton
public final class FrontEndThreads extends BaseThreadPool {
@Inject
public FrontEndThreads(ApplicationLifecycle lifecycle) {
super("Front-End-Pool", 50, lifecycle);
lifecycle.addStopHook(() -> {
try {
POOL.shutdownNow();
} catch (SecurityException ex) {
}
return CompletableFuture.completedFuture(null);
});
}
}

View File

@ -1,35 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.factory;
import com.gitpitch.models.Markdown;
import com.gitpitch.utils.MarkdownRenderer;
import javax.annotation.Nullable;
/*
* MarkdownModel factory.
*/
public interface MarkdownModelFactory {
Markdown create(@Nullable MarkdownRenderer mrndr);
}

View File

@ -1,52 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.filters;
import play.filters.gzip.GzipFilter;
import play.filters.headers.SecurityHeadersFilter;
import play.filters.hosts.AllowedHostsFilter;
import play.http.HttpFilters;
import play.mvc.EssentialFilter;
import javax.inject.Inject;
public class PitchFilters implements HttpFilters {
private EssentialFilter[] filters;
@Inject
public PitchFilters(SecurityHeadersFilter secHeadersFilter,
AllowedHostsFilter allowedHostsFilter,
GzipFilter gzipFilter) {
filters = new EssentialFilter[]{secHeadersFilter.asJava(),
allowedHostsFilter.asJava(),
gzipFilter.asJava()};
}
@Override
public EssentialFilter[] filters() {
return filters;
}
}

View File

@ -1,122 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git;
import com.gitpitch.utils.PitchParams;
import java.util.Map;
import java.util.HashMap;
/*
* Git Respository Service model.
*/
public class GRS {
private final String name;
private final String type;
private final String site;
private final String apiBase;
private final String apiToken;
private final String apiTokenHeader;
private final String rawBase;
private final String gistBase;
private final String branchDelim;
private final boolean isDefault;
private GRS(String name,
String type,
String site,
String apiBase,
String apiToken,
String apiTokenHeader,
String rawBase,
String gistBase,
String branchDelim,
boolean isDefault) {
this.name = name;
this.type = type;
this.site = site;
this.apiBase = apiBase;
this.apiToken = apiToken;
this.apiTokenHeader = apiTokenHeader;
this.rawBase = rawBase;
this.gistBase = gistBase;
this.branchDelim = branchDelim;
this.isDefault = isDefault;
}
public static GRS build(Map<String,String> grsCfg) {
String name = grsCfg.get("name");
String type = grsCfg.get("type");
String site = grsCfg.get("site");
String apiBase = grsCfg.get("apibase");
String apiToken = grsCfg.get("apitoken");
String apiTokenHeader = grsCfg.get("apitokenheader");
String rawBase = grsCfg.get("rawbase");
String gistBase = grsCfg.get("gistbase");
String branchDelim = grsCfg.get("branchdelim");
boolean isDefault = Boolean.parseBoolean(grsCfg.get("default"));
if(name != null && type != null && site != null &&
apiBase != null && rawBase != null) {
return new GRS(name, type, site, apiBase, apiToken,
apiTokenHeader, rawBase, gistBase, branchDelim, isDefault);
} else {
return null;
}
}
public String getName() { return name; }
public String getType() { return type; }
public String getSite() { return site; }
public String getApiBase() { return apiBase; }
public String getApiToken() { return apiToken; }
public String getApiTokenHeader() { return apiTokenHeader; }
public String getRawBase() { return rawBase; }
public String getGistBase() { return gistBase; }
public String compoundBranch(String branch) {
if(branch != null && branchDelim != null) {
return branch.replaceAll(branchDelim, COMPOUNDED_BRANCH);
} else {
return branch;
}
}
public boolean isDefault() { return isDefault; }
public Map<String,String> getHeaders() {
Map<String,String> hdrs = new HashMap<String,String>();
if(getApiToken() != null && getApiTokenHeader() != null) {
hdrs.put(getApiTokenHeader(), getApiToken());
}
return hdrs;
}
public String toString() {
return "GRS[ " + name + " ][ " + type + " ]";
}
private static final String COMPOUNDED_BRANCH = "/";
}

View File

@ -1,197 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git;
import com.gitpitch.git.vendors.*;
import com.gitpitch.services.DiskService;
import com.gitpitch.policies.Runtime;
import com.gitpitch.utils.PitchParams;
import java.util.*;
import java.util.stream.Collectors;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/*
* Git Repository Service manager.
*/
@Singleton
public class GRSManager {
private final Logger.ALogger log = Logger.of(this.getClass());
private final DiskService diskService;
private final Runtime runtime;
private final GitHub gitHubService;
private final GitLab gitLabService;
private final BitBucket bitBucketService;
private final Gitea giteaService;
private final Gogs gogsService;
private final GitBucket gitBucketService;
private final Map<String,GRS> grsStore = new HashMap<String,GRS>();
private GRS grsDefault;
@Inject
public GRSManager(DiskService diskService,
GitHub gitHubService,
GitLab gitLabService,
BitBucket bitBucketService,
Gitea giteaService,
Gogs gogsService,
GitBucket gitBucketService,
Runtime runtime) {
this.diskService = diskService;
this.gitHubService = gitHubService;
this.gitHubService.init(this, diskService);
this.gitLabService = gitLabService;
this.gitLabService.init(this, diskService);
this.bitBucketService = bitBucketService;
this.bitBucketService.init(this, diskService);
this.giteaService = giteaService;
this.giteaService.init(this, diskService);
this.gogsService = gogsService;
this.gogsService.init(this, diskService);
this.gitBucketService = gitBucketService;
this.gitBucketService.init(this, diskService);
this.runtime = runtime;
List grsCfg = runtime.configList("gitpitch.git.repo.services");
List<HashMap<String,String>> grsCfgList = (List<HashMap<String,String>>) grsCfg;
GRS fallback = GRS.build(GRS_FALLBACK);
for(HashMap<String,String> grsMap : grsCfgList) {
GRS grs = GRS.build(grsMap);
if(grs != null) {
grsStore.put(grs.getType(), grs);
if(grs.isDefault())
grsDefault = grs;
} else {
log.warn("rejecting: {}", grsMap);
}
}
if(grsStore.isEmpty()) {
grsStore.put(fallback.getType(), fallback);
grsDefault = fallback;
log.info("fallback: {}, type={}, true",
grsDefault.getName(), grsDefault.getType());
}
if(grsDefault == null) {
grsDefault = fallback;
}
grsStore.forEach((k,v) -> {
log.info("activating: {}, type={}, default={}",
v.getName(), k, v.isDefault());
});
}
public GRS get(PitchParams pp) {
return get(pp.grs);
}
public GRS get(String grsType) {
GRS grs = grsStore.get(grsType);
return (grs != null) ? grs : grsDefault;
}
public String getType(String grsType) {
GRS grs = grsStore.get(grsType);
return (grs != null) ? grs.getType() : grsDefault.getType();
}
public GRSService getService(GRS grs) {
GRSService service;
switch(grs.getType()) {
case GitHub.TYPE:
log.debug("getService: matching GitHub");
service = gitHubService;
break;
case GitLab.TYPE:
log.debug("getService: matching GitLab");
service = gitLabService;
break;
case BitBucket.TYPE:
log.debug("getService: matching BitBucket");
service = bitBucketService;
break;
case Gitea.TYPE:
log.debug("getService: matching Gitea");
service = giteaService;
break;
case Gogs.TYPE:
log.debug("getService: matching Gogs");
service = gogsService;
break;
case GitBucket.TYPE:
log.debug("getService: matching GitBucket");
service = gitBucketService;
break;
default:
log.debug("getService: defaulting GitHub");
service = gitHubService;
}
log.debug("getService: returning={}", service);
return service;
}
public List<GRS> listGRS() {
List<GRS> services = grsStore.entrySet()
.stream()
.map(Map.Entry::getValue)
.collect(Collectors.toList());
log.debug("listGRS: {}", services);
return services;
}
static Map<String,String> GRS_FALLBACK = new HashMap<String, String>();
static {
GRS_FALLBACK.put("name", "GitHub");
GRS_FALLBACK.put("type", "github");
GRS_FALLBACK.put("apibase", "https://api.github.com/");
GRS_FALLBACK.put("apitoken", null);
GRS_FALLBACK.put("rawbase", "https://raw.githubusercontent.com/");
GRS_FALLBACK.put("default", "true");
}
}

View File

@ -1,146 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git;
import com.gitpitch.git.*;
import com.gitpitch.models.GitRepoModel;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.services.DiskService;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicInteger;
import com.fasterxml.jackson.databind.JsonNode;
import play.Logger;
import play.Logger.ALogger;
/*
* Git Respository Service common interface.
*/
public abstract class GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
protected final AtomicInteger cacheBypass = new AtomicInteger();
protected GRSManager grsManager;
protected DiskService diskService;
public void init(GRSManager grsManager,
DiskService diskService) {
this.grsManager = grsManager;
this.diskService = diskService;
}
/*
* Return true if apiPath is a call on this GRSService instance.
*/
public boolean call(PitchParams pp, String apiPath) {
if(apiPath != null) {
GRS grs = grsManager.get(pp);
return apiPath.startsWith(grs.getApiBase()) ||
apiPath.startsWith(grs.getRawBase());
} else {
return false;
}
}
/*
* Return zero if file download completes successfully.
*/
public int download(PitchParams pp, String filename, String filePath) {
int status = 999;
GRS grs = grsManager.get(pp);
GRSService grsService = grsManager.getService(grs);
Path branchPath = diskService.ensure(pp);
String grsLink = raw(pp, filePath, true);
log.debug("download: grsLink={}", grsLink);
if (grsService.call(pp, grsLink)) {
status = diskService.download(pp,
branchPath,
grsLink,
filename,
grs.getHeaders());
}
log.debug("download: returning status={}", status);
return status;
}
/*
* Return model representing Git repository meta-data.
*/
public abstract GitRepoModel model(PitchParams pp, JsonNode json);
/*
* Return Raw API path for /user/repo/branch.
*/
public abstract String raw(PitchParams pp);
/*
* Return Raw API path for /user/repo/branch/filename.
*/
public String raw(PitchParams pp, String filename) {
return raw(pp, filename, false);
}
/*
* Return Raw API path for /user/repo/branch/filename with
* optional query param used to bypass GRS API caching.
*/
public String raw(PitchParams pp,
String filename,
boolean bypassCache) {
if (bypassCache) {
return raw(pp) + filename +
"?gp=" + cacheBypass.getAndIncrement();
} else {
return raw(pp) + filename;
}
}
/*
* Return API path for repository meta call for /user/repo.
*/
public abstract String repo(PitchParams pp);
/*
* Return GIST API path for code snippet identified by gid.
*/
public String gist(PitchParams pp, String gid) {
return gist(pp, gid, null);
}
/*
* Return GIST API path for code snippet identified by
* file (fid) on code snippet (gid).
*/
public abstract String gist(PitchParams pp, String gid, String fid);
protected static final String SLASH = "/";
protected static final String NOT_FOUND = "#";
}

View File

@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.services.DiskService;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.file.Path;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* BitBucket API Service.
*/
@Singleton
public class BitBucket extends GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return BitBucketRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getRawBase())
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(BITBUCKET_RAW)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(BITBUCKET_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String gist(PitchParams pp, String gid, String fid) {
return NOT_FOUND;
}
public static final String TYPE = "bitbucket";
private static final String BITBUCKET_REPO_API = "repositories/";
private static final String BITBUCKET_RAW = "/raw/";
}

View File

@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.utils.PitchParams;
import com.fasterxml.jackson.databind.JsonNode;
import play.Logger;
import play.Logger.ALogger;
import javax.inject.Singleton;
/*
* GitBucket API Service.
*/
@Singleton
public class GitBucket extends GRSService {
private final ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return GitHubRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GITBUCKET_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(SLASH)
.append(GITBUCKET_RAW_API)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GITBUCKET_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String gist(PitchParams pp, String gid, String fid) {
return NOT_FOUND;
}
public static final String TYPE = "gitbucket";
private static final String GITBUCKET_REPO_API = "repos/";
private static final String GITBUCKET_RAW_API = "raw/";
}

View File

@ -1,94 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.services.DiskService;
import com.gitpitch.utils.PitchParams;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.file.Path;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* GitHub API Service.
*/
@Singleton
public class GitHub extends GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return GitHubRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getRawBase())
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(SLASH)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GITHUB_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String gist(PitchParams pp, String gid, String fid) {
GRS grs = grsManager.get(TYPE);
StringBuffer gistLink = new StringBuffer(grs.getGistBase())
.append(gid)
.append(SLASH)
.append(GITHUB_GIST_RAW);
if(fid != null) {
gistLink = gistLink.append(SLASH).append(fid);
}
return gistLink.toString();
}
public static final String TYPE = "github";
private static final String GITHUB_REPO_API = "repos/";
private static final String GITHUB_GIST_RAW = "raw";
}

View File

@ -1,92 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.services.DiskService;
import com.gitpitch.utils.PitchParams;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.file.Path;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* GitLab API Service.
*/
@Singleton
public class GitLab extends GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return GitLabRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getRawBase())
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(GITLAB_RAW)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GITLAB_PROJECTS_API)
.append(genProjectId(pp))
.toString();
}
private String genProjectId(PitchParams pp) {
String userRepo =
new StringBuffer(pp.user).append(SLASH)
.append(pp.repo)
.toString();
String pid = java.net.URLEncoder.encode(userRepo);
log.debug("genProjectId: pid={}", pid);
return pid;
}
public String gist(PitchParams pp, String gid, String fid) {
return NOT_FOUND;
}
public static final String TYPE = "gitlab";
private static final String GITLAB_PROJECTS_API = "projects/";
private static final String GITLAB_RAW = "/raw/";
}

View File

@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.services.DiskService;
import com.gitpitch.utils.PitchParams;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.file.Path;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* Gitea API Service.
*/
@Singleton
public class Gitea extends GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return GiteaRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getRawBase())
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(GITEA_RAW)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GITEA_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String gist(PitchParams pp, String gid, String fid) {
return NOT_FOUND;
}
public static final String TYPE = "gitea";
private static final String GITEA_REPO_API = "repos/";
private static final String GITEA_RAW = "/raw/branch/";
}

View File

@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.git.vendors;
import com.gitpitch.git.*;
import com.gitpitch.models.*;
import com.gitpitch.services.DiskService;
import com.gitpitch.utils.PitchParams;
import com.fasterxml.jackson.databind.JsonNode;
import java.nio.file.Path;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* Gogs API Service.
*/
@Singleton
public class Gogs extends GRSService {
private final Logger.ALogger log = Logger.of(this.getClass());
public GitRepoModel model(PitchParams pp, JsonNode json) {
return GogsRepoModel.build(pp, json);
}
public String raw(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getRawBase())
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(GOGS_RAW)
.append(grs.compoundBranch(pp.branch))
.append(SLASH)
.toString();
}
public String repo(PitchParams pp) {
GRS grs = grsManager.get(TYPE);
return new StringBuffer(grs.getApiBase())
.append(GOGS_REPO_API)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String gist(PitchParams pp, String gid, String fid) {
return NOT_FOUND;
}
public static final String TYPE = "gogs";
private static final String GOGS_REPO_API = "repos/";
private static final String GOGS_RAW = "/raw/";
}

View File

@ -1,93 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class BitBucketRepoModel extends GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Initialize instance of BitBucketRepoModel.
*/
private BitBucketRepoModel(PitchParams pp) {
this(pp, null);
}
/*
* Initialize instance of BitBucketRepoModel.
*/
private BitBucketRepoModel(PitchParams pp,
JsonNode json) {
this._pp = pp;
if(pp != null) {
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.toString();
this._cacheKey = genKey(pp);
}
/*
* Generate derived data on instance only if the BitBucket
* API JSON is available for processing.
*/
if (json != null) {
JsonNode ownerNode = json.findPath(OWNER);
this._type = ownerNode.findPath(TYPE).textValue();
this._desc = json.findPath(DESCRIPTION).textValue();
this._created = json.findPath(CREATED_ON).textValue();
this._updated = json.findPath(UPDATED_ON).textValue();
this._lang = json.findPath(LANGUAGE).textValue();
this._stars = 0;
this._forks = 0;
this._issues = 0;
this._hasWiki = json.findPath(HAS_WIKI).asBoolean();
this._hasPages = false;
this._private = json.findPath(IS_PRIVATE).asBoolean();
}
}
public static GitRepoModel build(PitchParams pp) {
return build(pp, null);
}
public static GitRepoModel build(PitchParams pp, JsonNode json) {
return new BitBucketRepoModel(pp, json);
}
}

View File

@ -1,93 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class GitHubRepoModel extends GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Initialize instance of GitHubRepoModel.
*/
private GitHubRepoModel(PitchParams pp) {
this(pp, null);
}
/*
* Initialize instance of GitHubRepoModel.
*/
private GitHubRepoModel(PitchParams pp,
JsonNode json) {
this._pp = pp;
if(pp != null) {
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.toString();
this._cacheKey = genKey(pp);
}
/*
* Generate derived data on instance only if the GitHub
* API JSON is available for processing.
*/
if (json != null) {
JsonNode ownerNode = json.findPath(OWNER);
this._type = ownerNode.findPath(TYPE).textValue();
this._desc = json.findPath(DESCRIPTION).textValue();
this._created = json.findPath(CREATED_AT).textValue();
this._updated = json.findPath(UPDATED_AT).textValue();
this._lang = json.findPath(LANGUAGE).textValue();
this._stars = json.findPath(STARGAZERS_COUNT).asInt();
this._forks = json.findPath(FORKS_COUNT).asInt();
this._issues = json.findPath(OPEN_ISSUES).asInt();
this._hasWiki = json.findPath(HAS_WIKI).asBoolean();
this._hasPages = json.findPath(HAS_PAGES).asBoolean();
this._private = json.findPath(PRIVATE).asBoolean();
}
}
public static GitRepoModel build(PitchParams pp) {
return build(pp, null);
}
public static GitRepoModel build(PitchParams pp, JsonNode json) {
return new GitHubRepoModel(pp, json);
}
}

View File

@ -1,96 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class GitLabRepoModel extends GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Initialize instance of GitLabRepoModel.
*/
private GitLabRepoModel(PitchParams pp) {
this(pp, null);
}
/*
* Initialize instance of GitLabRepoModel.
*/
private GitLabRepoModel(PitchParams pp,
JsonNode json) {
this._pp = pp;
if(pp != null) {
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.toString();
this._cacheKey = genKey(pp);
}
/*
* Generate derived data on instance only if the GitLab
* API JSON is available for processing.
*/
if (json != null) {
this._type = USER_TYPE;
this._desc = json.findPath(DESCRIPTION).textValue();
this._lang = null;
JsonNode namespaceNode = json.findPath(NAMESPACE);
if(namespaceNode != null) {
this._created = namespaceNode.findPath(CREATED_AT).textValue();
this._updated = namespaceNode.findPath(UPDATED_AT).textValue();
}
this._stars = json.findPath(STAR_COUNT).asInt();
this._forks = json.findPath(FORKS_COUNT).asInt();
this._issues = json.findPath(OPEN_ISSUES_COUNT).asInt();
this._hasWiki = json.findPath(WIKI_ENABLED).asBoolean();
this._hasPages = false;
this._private = json.findPath(VISIBILITY).textValue() != PUBLIC;
}
}
public static GitRepoModel build(PitchParams pp) {
return build(pp, null);
}
public static GitRepoModel build(PitchParams pp, JsonNode json) {
return new GitLabRepoModel(pp, json);
}
private static final String USER_TYPE = "User";
}

View File

@ -1,174 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public abstract class GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* PitchParams.
*/
protected PitchParams _pp;
/*
* Git repository owner type: User or Organization.
*/
protected String _type;
/*
* Git repository description.
*/
protected String _desc;
/*
* Git repository creation date.
*/
protected String _created;
/*
* Git repository last updated date.
*/
protected String _updated;
/*
* Git repository language.
*/
protected String _lang;
/*
* Git repository stargazers_count.
*/
protected int _stars;
/*
* Git repository forks_count.
*/
protected int _forks;
/*
* Git repository open issues count.
*/
protected int _issues;
/*
* Git repository has Wiki flag.
*/
protected boolean _hasWiki;
/*
* Git repository has Pages (website) flag.
*/
protected boolean _hasPages;
/*
* Derived immutable state.
*/
protected String _pretty;
protected String _cacheKey;
/*
* Git repo visibility.
*/
protected boolean _private;
/*
* Generate a key for querying the cache for matching GitRepoModel.
*/
public static String genKey(PitchParams pp) {
return new StringBuffer(MODEL_ID).append(SLASH)
.append(pp.grs)
.append(SLASH)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
}
public String owner() {
return _pp.user;
}
public String name() {
return _pp.repo;
}
public String description() {
return _desc;
}
public String lang() {
return _lang;
}
public boolean byOrg() {
return GIT_TYPE_ORG.equals(_type);
}
public int stargazers() {
return _stars;
}
public int forks() {
return _forks;
}
public String toString() {
return _pretty;
}
public String key() {
return _cacheKey;
}
/*
* Repo API JSON response property names.
*/
protected static final String OWNER = "owner";
protected static final String TYPE = "type";
protected static final String DESCRIPTION = "description";
protected static final String CREATED_AT = "created_at";
protected static final String UPDATED_AT = "updated_at";
protected static final String CREATED_ON = "created_on";
protected static final String UPDATED_ON = "updated_on";
protected static final String LANGUAGE = "language";
protected static final String STARGAZERS_COUNT = "stargazers_count";
protected static final String STAR_COUNT = "star_count";
protected static final String FORKS_COUNT = "forks_count";
protected static final String OPEN_ISSUES = "open_issues";
protected static final String OPEN_ISSUES_COUNT = "open_issues_count";
protected static final String HAS_WIKI = "has_wiki";
protected static final String WIKI_ENABLED = "wiki_enabled";
protected static final String HAS_PAGES = "has_pages";
protected static final String PUBLIC = "public";
protected static final String PRIVATE = "private";
protected static final String IS_PRIVATE = "is_private";
protected static final String NAMESPACE = "namespace";
protected static final String VISIBILITY = "visiblity";
protected static final String GIT_TYPE_ORG = "Organization";
protected static final String SLASH = "/";
/*
* Model prefix identifier for cache key generator.
*/
private static final String MODEL_ID = "GRM:";
}

View File

@ -1,145 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class GiteaRepoModel extends GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Initialize instance of GiteaRepoModel.
*/
private GiteaRepoModel(PitchParams pp) {
this(pp, null);
}
/*
* Initialize instance of GiteaRepoModel.
*/
private GiteaRepoModel(PitchParams pp, JsonNode json) {
this._pp = pp;
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.toString();
this._cacheKey = genKey(pp);
/*
* Generate derived data on instance only if the GitHub
* API JSON is available for processing.
*/
if (json != null) {
JsonNode ownerNode = json.findPath("owner");
this._type = null;
this._desc = json.findPath("description").textValue();
this._created = json.findPath("created_at").textValue();
this._updated = json.findPath("updated_at").textValue();
this._lang = null;
this._stars = json.findPath("stars_count").asInt();
this._forks = json.findPath("forks_count").asInt();
this._issues = json.findPath("open_issues.count").asInt();
this._hasWiki = false;
this._hasPages = false;
} else {
this._type = null;
this._desc = null;
this._created = null;
this._updated = null;
this._lang = null;
this._stars = 0;
this._forks = 0;
this._issues = 0;
this._hasWiki = false;
this._hasPages = false;
}
}
public static GitRepoModel build(PitchParams pp) {
return build(pp, null);
}
public static GitRepoModel build(PitchParams pp, JsonNode json) {
return new GiteaRepoModel(pp, json);
}
public String owner() {
return _pp.user;
}
public String name() {
return _pp.repo;
}
public String description() {
return _desc;
}
public String lang() {
return _lang;
}
public boolean byOrg() {
return false;
}
public int stargazers() {
return _stars;
}
public int forks() {
return _forks;
}
public String toString() {
return _pretty;
}
public String key() {
return _cacheKey;
}
}

View File

@ -1,145 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.Logger.ALogger;
import java.util.*;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class GogsRepoModel extends GitRepoModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Initialize instance of GogsRepoModel.
*/
private GogsRepoModel(PitchParams pp) {
this(pp, null);
}
/*
* Initialize instance of GogsRepoModel.
*/
private GogsRepoModel(PitchParams pp, JsonNode json) {
this._pp = pp;
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.toString();
this._cacheKey = genKey(pp);
/*
* Generate derived data on instance only if the GitHub
* API JSON is available for processing.
*/
if (json != null) {
JsonNode ownerNode = json.findPath("owner");
this._type = null;
this._desc = json.findPath("description").textValue();
this._created = json.findPath("created_at").textValue();
this._updated = json.findPath("updated_at").textValue();
this._lang = null;
this._stars = json.findPath("stars_count").asInt();
this._forks = json.findPath("forks_count").asInt();
this._issues = json.findPath("open_issues.count").asInt();
this._hasWiki = false;
this._hasPages = false;
} else {
this._type = null;
this._desc = null;
this._created = null;
this._updated = null;
this._lang = null;
this._stars = 0;
this._forks = 0;
this._issues = 0;
this._hasWiki = false;
this._hasPages = false;
}
}
public static GitRepoModel build(PitchParams pp) {
return build(pp, null);
}
public static GitRepoModel build(PitchParams pp, JsonNode json) {
return new GogsRepoModel(pp, json);
}
public String owner() {
return _pp.user;
}
public String name() {
return _pp.repo;
}
public String description() {
return _desc;
}
public String lang() {
return _lang;
}
public boolean byOrg() {
return false;
}
public int stargazers() {
return _stars;
}
public int forks() {
return _forks;
}
public String toString() {
return _pretty;
}
public String key() {
return _cacheKey;
}
}

View File

@ -1,33 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
/*
* Markdown model interface.
*/
public interface Markdown {
public String produce();
public String offline(String md);
public String offlineAssets(String md);
}

View File

@ -1,745 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.utils.*;
import com.gitpitch.services.ImageService;
import com.gitpitch.services.VideoService;
import com.gitpitch.services.GISTService;
import com.gitpitch.services.CodeService;
import com.gitpitch.services.ShortcutsService;
import com.gitpitch.services.SlideService;
import com.gitpitch.git.GRSManager;
import org.apache.commons.io.FilenameUtils;
import com.google.inject.assistedinject.Assisted;
import javax.annotation.Nullable;
import play.Logger;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.*;
/*
* Rendering model for PITCHME.md markdown.
*/
public class MarkdownModel implements Markdown {
private final Logger.ALogger log = Logger.of(this.getClass());
private final ImageService imageService;
private final VideoService videoService;
private final GISTService gistService;
private final CodeService codeService;
private final ShortcutsService shortcutsService;
private final SlideService slideService;
private final GRSManager grsManager;
private final MarkdownRenderer mrndr;
private final String markdown;
private String hSlideDelim = HSLIDE_DELIM_DEFAULT;
private String vSlideDelim = VSLIDE_DELIM_DEFAULT;
@Inject
public MarkdownModel(ImageService imageService,
VideoService videoService,
GISTService gistService,
CodeService codeService,
ShortcutsService shortcutsService,
SlideService slideService,
GRSManager grsManager,
@Nullable @Assisted MarkdownRenderer mrndr) {
this.imageService = imageService;
this.videoService = videoService;
this.gistService = gistService;
this.codeService = codeService;
this.shortcutsService = shortcutsService;
this.slideService = slideService;
this.grsManager = grsManager;
this.mrndr = mrndr;
String consumed = null;
if(mrndr != null) {
String gitRawBase = mrndr.gitRawBase();
Path mdPath = mrndr.filePath(PITCHME_MD);
File mdFile = mdPath.toFile();
if (mdFile.exists()) {
Optional<SlideshowModel> ssmo = mrndr.ssm();
final PitchParams pp =
ssmo.isPresent() ? ssmo.get().params() : null;
final YAMLOptions yOpts =
ssmo.isPresent() ? ssmo.get().options() : null;
if(yOpts != null) {
hSlideDelim = yOpts.hasHorzDelim(pp) ?
yOpts.fetchHorzDelim(pp) : HSLIDE_DELIM_DEFAULT;
vSlideDelim = yOpts.hasVertDelim(pp) ?
yOpts.fetchVertDelim(pp) : VSLIDE_DELIM_DEFAULT;
}
try (Stream<String> stream = Files.lines(mdPath)) {
consumed = stream.map(md -> {
return process(md, pp, yOpts, gitRawBase);
}).map(md -> {
return shortcutsService.process(md, pp, yOpts);
}).collect(Collectors.joining("\n"));
consumed = postProcess(consumed, pp, yOpts, gitRawBase);
} catch (Exception mex) {
log.warn("Markdown processing ex={}", mex);
consumed = "PITCHME.md could not be parsed.";
}
} else {
log.warn("Markdown file does not exist, {}", mdFile);
}
}
this.markdown = consumed;
}
/*
* Process text, image, video, gist, and code content
* in PITCHME.md for online viewing.
*/
private String process(String md,
PitchParams pp,
YAMLOptions yOpts,
String gitRawBase) {
md = processBackwardCompatDelim(md);
if (slideDelimFound(md)) {
/*
* Clean only delimiter fragments of whitespace
* noise before processing. Preserve end-of-line
* characters on all non-delimiter fragments.
*/
md = md.trim();
DelimParams dp = DelimParams.build(md);
if (videoDelimFound(dp)) {
/*
* Inject slide specific video background:
*
* <!-- .slide: data-background-video="vidUrl" -->
*/
return new StringBuffer(delimiter(md))
.append(videoService.buildBackground(md,
dp, pp, this))
.toString();
} else if (imageDelimFound(dp)) {
/*
* Inject slide specific image background:
*
* <!-- .slide: data-background-image="imgUrl" -->
*/
String defaultBgSize = (yOpts != null) ?
yOpts.fetchImageBgSize(pp) : YAMLOptions.DEFAULT_BG_SIZE;
String defaultBgColor = (yOpts != null) ?
yOpts.fetchImageBgColor(pp) : YAMLOptions.DEFAULT_BG_COLOR;
String defaultBgPosition = (yOpts != null) ?
yOpts.fetchImageBgPosition(pp) : YAMLOptions.DEFAULT_BG_POSITION;
String defaultBgRepeat = (yOpts != null) ?
yOpts.fetchImageBgRepeat(pp) : YAMLOptions.DEFAULT_BG_REPEAT;
String defaultBgTransition = (yOpts != null) ?
yOpts.fetchTransition(pp) : YAMLOptions.DEFAULT_TRANSITION;
return new StringBuffer(delimiter(md))
.append(imageService.buildBackground(md,
dp,
pp,
defaultBgSize,
defaultBgColor,
defaultBgPosition,
defaultBgRepeat,
defaultBgTransition,
this)).toString();
} else if (gistDelimFound(dp)) {
return gistService.build(md, dp, pp, yOpts, this);
} else if(codeDelimFound(dp)) {
return codeService.build(md, dp, pp, yOpts, this);
} else if(colorDelimFound(dp)) {
return slideService.buildColorBackground(md, dp, pp, yOpts, this);
}
if (yOpts != null && yOpts.hasImageBg()) {
/*
* Inject slideshow-wide background:
*
* <!-- .slide: data-background-image="imgUrl" -->
*/
return new StringBuffer(md)
.append(imageService.buildBackground(pp, yOpts))
.toString();
} else {
/*
* No customization on slide delimiter or background,
* return unmodified.
*/
return md;
}
} else if (markdownLinkFound(md)) {
/*
* Link found in markdown fragment, process.
*/
int delim = md.indexOf(MD_LINK_DELIM);
if (delim == NOT_FOUND) {
/*
* Valid link syntax not found, return unmodified.
*/
return md;
} else {
/*
* Valid link syntax found, now process link to
* handle absolute, (GitHub) relative and video links.
*/
String splitLeft = md.substring(0, delim + 2);
String splitRight = md.substring(delim + 2);
/*
* Clone and clean splitRight string to begin
* extraction of the pitchLink.
*/
String pitchLink = cloneLink(splitRight);
pitchLink = extractLink(pitchLink, gitRawBase);
if (videoService.isVideo(pitchLink)) {
return videoService.buildVideo(pitchLink);
} else if (linkAbsolute(splitRight)) {
return md;
} else {
return splitLeft + gitRawBase + splitRight;
}
}
} else if(imageService.tagFound(md)) {
String tagLink = imageService.tagLink(md);
if (linkAbsolute(tagLink)) {
return md;
} else {
String absTagLink = gitRawBase + tagLink;
return md.replace(tagLink, absTagLink);
}
} else if(shortcutsService.titleHintFound(md)) {
return shortcutsService.expandTitleHint(md);
} else if(shortcutsService.listFragmentFound(md)) {
return shortcutsService.expandListFragment(md);
} else if(shortcutsService.codeFragmentFound(md)) {
return shortcutsService.expandCodeFragment(md);
} else {
/*
* Link-free markdown, return unmodified.
*/
return md;
}
}
public String produce() {
return markdown;
}
/*
* Process text, image, video, gist, and code content
* in PITCHME.md for offline viewing.
*/
public String offline(String md) {
if (videoService.found(md)) {
return videoService.offline();
} else if (gistMarkdown(md)) {
return gistService.offline();
} else if (imageService.background(md)) {
return imageService.buildBackgroundOffline(md);
} else if (imageService.inline(md)) {
/*
* Link found in markdown fragment, process.
*/
int delim = md.indexOf(MD_LINK_DELIM);
if (delim == NOT_FOUND) {
/*
* Valid link syntax not found, return unmodified.
*/
return md;
} else {
/*
* Valid link syntax found, now process link to
* handle absolute, (GitHub) relative and video links.
*/
String splitLeft = md.substring(0, delim + 2);
String splitRight = md.substring(delim + 2);
/*
* Clone and clean splitRight string to begin
* extraction of the pitchLink.
*/
String pitchLink = cloneLink(splitRight);
pitchLink = extractLink(pitchLink, null);
String imageName = FilenameUtils.getName(pitchLink);
return imageService.buildInlineOffline(imageName);
}
} else if(imageService.tagFound(md)) {
return imageService.buildTagOffline(md);
} else {
/*
* Link-free markdown, return unmodified.
*/
return md;
}
}
/*
* Return image asset URL from Markdown fragment.
*/
public String offlineAssets(String md) {
if (imageService.background(md)) {
String frag = md.substring(MD_IMAGE_OPEN.length());
String url = frag.substring(0, frag.indexOf("\""));
return url;
} else if (imageService.inline(md)) {
/*
* Link found in markdown fragment, process.
*/
int delim = md.indexOf(MD_LINK_DELIM);
if (delim == NOT_FOUND) {
/*
* Valid link syntax not found, return unmodified.
*/
return null;
} else {
/*
* Valid link syntax found, now process link to
* handle absolute, (GitHub) relative and video links.
*/
String splitLeft = md.substring(0, delim + 2);
String splitRight = md.substring(delim + 2);
/*
* Clone and clean splitRight string to begin
* extraction of the pitchLink.
*/
String pitchLink = cloneLink(splitRight);
int spaceIdx = pitchLink.indexOf(MD_LINK_SPACE);
int brcktIdx = pitchLink.indexOf(MD_LINK_BRCKT);
String origLink = null;
if (spaceIdx == NOT_FOUND || spaceIdx > brcktIdx) {
origLink = pitchLink.substring(0, brcktIdx);
} else {
origLink = pitchLink.substring(0, spaceIdx);
}
return origLink;
}
} if(imageService.tagFound(md)) {
/*
* Img tag found in markdown fragment, process.
*/
return imageService.tagLink(md);
} else {
return null;
}
}
private boolean imageDelimFound(DelimParams dp) {
return dp.get(DELIM_QUERY_IMAGE) != null;
}
private boolean videoDelimFound(DelimParams dp) {
return dp.get(DELIM_QUERY_VIDEO) != null;
}
private boolean gistDelimFound(DelimParams dp) {
return dp.get(DELIM_QUERY_GIST) != null;
}
private boolean codeDelimFound(DelimParams dp) {
return dp.get(DELIM_QUERY_CODE) != null;
}
private boolean colorDelimFound(DelimParams dp) {
return dp.get(DELIM_QUERY_COLOR) != null;
}
private String delimiter(String md) {
return (md.startsWith(hSlideDelim)) ? horizDelim() : vertDelim();
}
private boolean slideDelimFound(String md) {
return md.startsWith(horizDelim()) || md.startsWith(vertDelim());
}
private boolean markdownLinkFound(String md) {
return md.startsWith(MD_LINK_OPEN);
}
private boolean gistMarkdown(String md) {
return md.contains(DATA_GIST_ATTR);
}
private String cloneLink(String link) {
String cloned = new String(link);
/*
* Strip slash prefix from relative links.
*/
if (cloned.startsWith(MD_LINK_SLASH)) {
return cloned.substring(1);
} else {
return cloned;
}
}
private String extractLink(String link, String gitRawBase) {
try {
int spaceIdx = link.indexOf(MD_LINK_SPACE);
int brcktIdx = link.indexOf(MD_LINK_BRCKT);
String origLink = null;
if (spaceIdx == NOT_FOUND || spaceIdx > brcktIdx) {
origLink = link.substring(0, brcktIdx);
} else {
origLink = link.substring(0, spaceIdx);
}
if (linkAbsolute(link)) {
link = origLink;
} else {
link = gitRawBase + origLink;
}
return link;
} catch (Exception lex) {
log.warn("extractLink: link={}, ex={}", link, lex);
}
return null;
}
private String postProcess(String md,
PitchParams pp,
YAMLOptions yOpts,
String gitRawBase) {
if (yOpts != null && yOpts.hasImageBg()) {
if (!delimOnFirstSlide(md)) {
/*
* Inject slideshow-wide background for
* implicit delim on first slide in the slideshow.
*/
md = imageService.buildBackground(pp, yOpts) + md;
}
}
if (delimOnFirstSlide(md)) {
int nIndex = md.indexOf(MD_SPACER);
if (nIndex > 0) {
String slimMd = md.substring(nIndex);
md = slimMd;
}
}
return md;
}
private boolean delimOnFirstSlide(String md) {
return (md.startsWith(horizDelim()) || md.startsWith(vertDelim()));
}
public boolean isHorizontal(String md) {
return (md.startsWith(horizDelim())) ? true : false;
}
public boolean linkAbsolute(String link) {
return link.startsWith(MD_LINK_ABS);
}
public String linkLive(PitchParams pp, String linkBase) {
try {
linkBase = linkBase.replaceAll(MD_LINK_SPACE, ENCODED_SPACE);
if (linkAbsolute(linkBase)) {
return linkBase;
} else {
return grsManager.getService(grsManager.get(pp))
.raw(pp, linkBase);
}
} catch (Exception lex) {
log.warn("linkLive: ex={}", lex);
return "#";
}
}
public String extractDelim(String md) {
return isHorizontal(md) ? horizDelim() : vertDelim();
}
/*
* Generate a key for querying the cache for matching MarkdownModel.
*/
public static String genKey(PitchParams pp) {
return new StringBuffer(MODEL_ID).append(SLASH)
.append(pp.grs)
.append(SLASH)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(PARAM_BRANCH)
.append(pp.branch)
.append(PARAM_PITCHME)
.append(pp.pitchme)
.toString();
}
public String horizDelim() {
return hSlideDelim;
}
public String vertDelim() {
return vSlideDelim;
}
public String horizImageDelim() {
return horizDelim() + MD_HSLIDE_IMAGE;
}
public String vertImageDelim() {
return vertDelim() + MD_VSLIDE_IMAGE;
}
public String horizVideoDelim() {
return horizDelim() + MD_HSLIDE_VIDEO;
}
public String vertVideoDelim() {
return vertDelim() + MD_VSLIDE_VIDEO;
}
public String horizGISTDelim() {
return horizDelim() + MD_HSLIDE_GIST;
}
public String vertGISTDelim() {
return vertDelim() + MD_VSLIDE_GIST;
}
public String horizCodeDelim() {
return horizDelim() + MD_HSLIDE_CODE;
}
public String vertCodeDelim() {
return vertDelim() + MD_VSLIDE_CODE;
}
/*
* The initial releases of GitPitch used #HSLIDE and #VSLIDE
* as default delimiters. To provide backwards compatability
* for older presentations, when these old delimters are
* detected within PITCHME.md we auto-translate these old
* delimiters to the current defaults HSLIDE|VSLIDE_DELIM_DEFAULT.
*/
private String processBackwardCompatDelim(String md) {
try {
if(md.startsWith(HSLIDE_DELIM_BACK_COMPAT)) {
md = md.replaceFirst(HSLIDE_DELIM_BACK_COMPAT,
HSLIDE_DELIM_DEFAULT);
} else
if(md.startsWith(VSLIDE_DELIM_BACK_COMPAT)) {
md = md.replaceFirst(VSLIDE_DELIM_BACK_COMPAT,
VSLIDE_DELIM_DEFAULT);
}
} catch(Exception bcex) {
return md;
}
return md;
}
/*
* Markdown Parsing Identifiers | Delimiters.
*/
public static final String HSLIDE_DELIM_DEFAULT = "---";
public static final String VSLIDE_DELIM_DEFAULT = "+++";
public static final String HSLIDE_REGEX_DEFAULT = null;
public static final String VSLIDE_REGEX_DEFAULT = "\\+\\+\\+";
public static final String HSLIDE_DELIM_BACK_COMPAT = "#HSLIDE";
public static final String VSLIDE_DELIM_BACK_COMPAT = "#VSLIDE";
public static final String DELIM_QUERY_IMAGE = "image";
public static final String DELIM_QUERY_VIDEO = "video";
public static final String DELIM_QUERY_LOOP = "loop";
public static final String DELIM_QUERY_MUTED = "muted";
public static final String DELIM_QUERY_GIST = "gist";
public static final String DELIM_QUERY_CODE = "code";
public static final String DELIM_QUERY_LANG = "lang";
public static final String DELIM_QUERY_SIZE = "size";
public static final String DELIM_QUERY_COLOR = "color";
public static final String DELIM_QUERY_POSITION = "position";
public static final String DELIM_QUERY_REPEAT = "repeat";
public static final String DELIM_QUERY_TRANSITION = "transition";
public static final String DELIM_QUERY_FILE = "file";
public static final String DELIM_QUERY_TITLE = "title";
public static final String MD_LINK_OPEN = "![";
public static final String MD_ANCHOR_OPEN = "[";
public static final String MD_IMAGE_OPEN =
"<!-- .slide: data-background-image=\"";
public static final String MD_VIDEO_OPEN =
"<!-- .slide: data-background-video=\"";
public static final String MD_VIDEO_OPEN_END = "\" ";
public static final String MD_VIDEO_LOOP =
" data-background-video-loop=\"true\" ";
public static final String MD_VIDEO_MUTED =
" data-background-video-muted=\"true\" ";
public static final String MD_VIDEO_CLOSE = " -->";
public static final String MD_IFRAME_OPEN =
"<!-- .slide: data-background-iframe=\"";
public static final String MD_IMAGE_SIZE =
"\" data-background-size=\"";
public static final String MD_IMAGE_COLOR =
"\" data-background-color=\"";
public static final String MD_IMAGE_POSITION =
"\" data-background-position=\"";
public static final String MD_IMAGE_REPEAT =
"\" data-background-repeat=\"";
public static final String MD_IMAGE_TRANSITION =
"\" data-background-transition=\"";
public static final String MD_BG_COLOR =
"<!-- .slide: data-background=\"";
public static final String MD_CLOSER = "\" -->";
public static final String MD_SPACER = "\n";
public static final String DATA_IMAGE_ATTR = "data-background-image=";
public static final String MD_LIST_FRAG_OPEN = "- ";
public static final String MD_LIST_FRAG_CLOSE = "|";
public static final String MD_CODE_FRAG_OPEN = "@[";
public static final String MD_CODE_FRAG_CLOSE = "]";
public static final String MD_CODE_FRAG_NOTE_OPEN = "(";
public static final String MD_CODE_FRAG_NOTE_CLOSE = ")";
public static final String MD_CODE_BLOCK_OPEN = "```";
public static final String MD_CODE_BLOCK_CLOSE = "```";
public static final String MD_TITLE_HINT_OPEN = "@title[";
public static final String MD_TITLE_HINT_CLOSE = "]";
public static final String MD_FA_OPEN = "@fa[";
public static final String MD_FA_CLOSE = "]";
public static final String MD_FA_NOTE_OPEN = "(";
public static final String MD_FA_NOTE_CLOSE = ")";
private static final String MD_HSLIDE_IMAGE = "?image=";
private static final String MD_VSLIDE_IMAGE = "?image=";
private static final String MD_HSLIDE_VIDEO = "?video=";
private static final String MD_VSLIDE_VIDEO = "?video=";
private static final String MD_HSLIDE_GIST = "?gist=";
private static final String MD_VSLIDE_GIST = "?gist=";
private static final String MD_HSLIDE_CODE = "?code=";
private static final String MD_VSLIDE_CODE = "?code=";
private static final String SLASH = "/";
private static final String PARAM_BRANCH = "?b=";
private static final String PARAM_PITCHME = "&p=";
private static final String MD_LINK_DELIM = "](";
private static final String MD_LINK_ABS = "http";
private static final String MD_LINK_SLASH = "/";
private static final String MD_LINK_SPACE = " ";
private static final String MD_LINK_BRCKT = ")";
private static final String MD_LINK_MP4 = "mp4";
private static final String DATA_GIST_ATTR = "data-gist=";
private static final String HTML_ANCHOR_OPEN =
"<a target=\"_blank\" href=\"";
private static final String HTML_ANCHOR_MID = "\">";
private static final String HTML_ANCHOR_CLOSE = "</a>";
private static final int NOT_FOUND = -1;
private static final String ENCODED_SPACE = "%20";
/*
* Model prefix identifier for cache key generator.
*/
private static final String MODEL_ID = "MDM:";
private static final String PITCHME_MD = "PITCHME.md";
}

View File

@ -1,643 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.models;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.git.GRSService;
import com.gitpitch.services.DiskService;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.YAMLOptions;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import play.Logger;
import play.Logger.ALogger;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class SlideshowModel {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Parameter values passed on GitPitch API call.
*/
private final PitchParams _pp;
/*
* PITCHME.yaml options.
*/
private final YAMLOptions _yOpts;
/*
* GitPitch API /api/markdown/{user}/{repo}?b={branch}.
*/
private final String _fetchMarkdown;
/*
* Derived immutable state.
*/
private final String _pretty;
private final String _cacheKey;
private SlideshowModel(PitchParams pp,
YAMLOptions yOpts) {
this._pp = pp;
this._yOpts = yOpts;
this._fetchMarkdown =
com.gitpitch.controllers.routes.PitchController.markdown(pp.grs,
pp.user,
pp.repo,
pp.branch,
pp.pitchme).url();
this._pretty = new StringBuffer(SLASH)
.append(this._pp.user)
.append(SLASH)
.append(this._pp.repo)
.append(PARAM_BRANCH)
.append(this._pp.branch)
.append(PARAM_PITCHME)
.append(this._pp.pitchme)
.toString();
this._cacheKey = genKey(pp);
}
public static SlideshowModel build(PitchParams pp,
boolean yamlFound,
GRSService grsService,
DiskService diskService) {
YAMLOptions yOpts =
yamlFound ? YAMLOptions.build(pp, grsService, diskService) : null;
return new SlideshowModel(pp, yOpts);
}
/*
* Generate a key for querying the cache for matching SlideshowModel.
*/
public static String genKey(PitchParams pp) {
return new StringBuffer(MODEL_ID).append(SLASH)
.append(pp.grs)
.append(SLASH)
.append(pp.user)
.append(SLASH)
.append(pp.repo)
.append(PARAM_BRANCH)
.append(pp.branch)
.append(PARAM_PITCHME)
.append(pp.pitchme)
.toString();
}
public SlideshowModel clone(PitchParams pp) {
return new SlideshowModel(pp, this._yOpts);
}
/*
* Return PitchParams instance on SlideshowModel.
*/
public PitchParams params() {
return _pp;
}
/*
* Return YAMLOptions instance on SlideshowModel.
*/
public YAMLOptions options() {
return _yOpts;
}
/*
* Return true if custom theme in use.
*/
public boolean fixedTheme() {
return (_yOpts != null) ?
_yOpts.fixedTheme(params()) : false;
}
/*
* Return active theme name for slideshow.
*/
public String fetchTheme() {
return (_yOpts != null) ? _yOpts.fetchTheme(params()) :
_pp.theme;
}
/*
* Return active theme.css for slideshow.
*/
public String fetchThemeCSS() {
return (_yOpts != null) ? _yOpts.fetchThemeCSS(params()) :
PitchParams.fetchThemeCSS(_pp.theme);
}
/*
* Return theme override css for slideshow.
*/
public boolean hasThemeOverride() {
return (_yOpts != null) ?
_yOpts.hasThemeOverride(params()) : false;
}
/*
* Return theme override css for slideshow.
*/
public String fetchThemeOverride() {
String customCSS = null;
if(hasThemeOverride()) {
String oride = _yOpts.fetchThemeOverride(params());
try {
customCSS = IOUtils.toString(new URL(oride),
Charset.forName("UTF-8"));
} catch(Exception ioex) {}
}
log.debug("fetchThemeOverride: customCSS={}", customCSS);
return customCSS;
}
/*
* Return active theme font for slideshow.
*/
public String fetchThemeFont() {
String font = THEME_FONTS.get(fetchTheme());
return (font != null) ? font : THEME_FONT_DEFAULT;
}
/*
* Return active theme font color inverse for slideshow.
*/
public String fetchThemeFontColorInverse() {
boolean darkTheme = PitchParams.isDarkTheme(fetchTheme());
return darkTheme ? THEME_DARK_COLOR_INVERSE :
THEME_LIGHT_COLOR_INVERSE;
}
public boolean isDarkTheme() {
return PitchParams.isDarkTheme(fetchTheme());
}
/*
* Return true if "layout" in *-left.
*/
public boolean isLeftLayout() {
return (_yOpts != null) ? _yOpts.isLeftLayout(params()) : false;
}
/*
* Return true if "layout" in *-right.
*/
public boolean isRightLayout() {
return (_yOpts != null) ? _yOpts.isRightLayout(params()) : false;
}
/*
* Return true if "logo" defined in PITCHME.yaml.
*/
public boolean hasLogo() {
return (_yOpts != null) ? _yOpts.hasLogo() : false;
}
/*
* Return "logo" defined in PITCHME.yaml.
*/
public String fetchLogo() {
return (_yOpts != null) ? _yOpts.fetchLogo(params()) : "#";
}
/*
* Return "logo" filename defined in PITCHME.yaml.
*/
public String fetchLogoName() {
return (_yOpts != null) ?
FilenameUtils.getName(_yOpts.fetchLogo(params())) : "#";
}
/*
* Return "logo-position" defined in PITCHME.yaml.
*/
public boolean hasLogoPosition() {
return (_yOpts != null) ? _yOpts.hasLogoPosition() : false;
}
/*
* Return "logo-position" defined in PITCHME.yaml.
*/
public String fetchLogoPosition() {
String position = _yOpts.fetchLogoPosition(params());
return LOGO_POSITIONS.get(position);
}
/*
* Return true if "footnote" defined in PITCHME.yaml.
*/
public boolean hasFootnote() {
return (_yOpts != null) ? _yOpts.hasFootnote(params()) : false;
}
/*
* Return "footnote" defined in PITCHME.yaml.
*/
public String fetchFootnote() {
return (_yOpts != null) ?
_yOpts.fetchFootnote(params()) : "Footnote undefined.";
}
/*
* Return markdown for slideshow.
*/
public String fetchMarkdown() {
return _fetchMarkdown;
}
/*
* Return true if slideshow speaker notes should be displayed.
*/
public boolean showNotes() {
return (_pp != null) ? Boolean.parseBoolean(_pp.notes) : false;
}
/*
* Return "transition" defined in PITCHME.yaml.
*/
public String fetchTransition() {
return (_yOpts != null) ? _yOpts.fetchTransition(params()) :
YAMLOptions.DEFAULT_TRANSITION;
}
/*
* Return "controls-layout" defined in PITCHME.yaml.
*/
public String fetchControlsLayout() {
String layout = (_yOpts != null) ?
_yOpts.fetchControlsLayout(params()) :
YAMLOptions.DEFAULT_CONTROLS_LAYOUT;
// Auto-relocate controls to 'edges' if logo-position is bottom-right.
if(_yOpts != null && hasLogoPosition()) {
String position = _yOpts.fetchLogoPosition(params());
if(YAMLOptions.DEFAULT_CONTROLS_LAYOUT.equals(position)) {
layout = YAMLOptions.EDGES_CONTROLS_LAYOUT;
}
}
return layout;
}
/*
* Return "autoslide" defined in PITCHME.yaml.
*/
public int fetchAutoSlide(boolean printing) {
if(printing)
return 0; // Disable auto-slide when printing.
else
return (_yOpts != null) ? _yOpts.fetchAutoSlide(params()) : 0;
}
/*
* Return "vertical-center" defined in PITCHME.yaml.
*/
public boolean fetchVerticalCenter() {
boolean vc = true;
if(_yOpts == null) {
vc = true;
} else
if(_yOpts.isTopLayout(params())) {
vc = false;
} else {
vc = _yOpts.fetchVerticalCenter(params());
}
return vc;
}
/*
* Return "loop" defined in PITCHME.yaml.
*/
public boolean fetchLoop() {
return (_yOpts != null) ? _yOpts.fetchLoop(params()) : false;
}
/*
* Return "remote-control" defined in PITCHME.yaml.
*/
public boolean remoteControlEnabled() {
return (_yOpts != null) ? _yOpts.fetchRemoteControl(params()) : false;
}
/*
* Return "remote-control-prevkey" defined in PITCHME.yaml.
*/
public int remoteControlPrevKey() {
int prevKeyCode = DEFAULT_PREV_KEYCODE;
if(_yOpts != null) {
prevKeyCode = _yOpts.fetchRemoteControlPrevKey(params());
}
return prevKeyCode != 0 ? prevKeyCode : DEFAULT_PREV_KEYCODE;
}
/*
* Return "remote-control-nextkey" defined in PITCHME.yaml.
*/
public int remoteControlNextKey() {
int nextKeyCode = DEFAULT_NEXT_KEYCODE;
if(_yOpts != null) {
nextKeyCode = _yOpts.fetchRemoteControlNextKey(params());
}
return nextKeyCode != 0 ? nextKeyCode : DEFAULT_NEXT_KEYCODE;
}
/*
* Return "rtl" defined in PITCHME.yaml.
*/
public boolean fetchRTL() {
return (_yOpts != null) ? _yOpts.fetchRTL(params()) : false;
}
/*
* Return "shuffle" defined in PITCHME.yaml.
*/
public boolean fetchShuffle() {
return (_yOpts != null) ? _yOpts.fetchShuffle(params()) : false;
}
/*
* Return "mousewheel" defined in PITCHME.yaml.
*/
public boolean fetchMouseWheel() {
return (_yOpts != null) ? _yOpts.fetchMouseWheel(params()) : false;
}
/*
* Return true if "charts" defined in PITCHME.yaml.
*/
public boolean chartsEnabled() {
return (_yOpts != null) ? _yOpts.fetchCharts(params()) : false;
}
/*
* Return true if "mathjax" defined in PITCHME.yaml.
*/
public boolean mathEnabled() {
return (_yOpts != null) ? _yOpts.mathEnabled(params()) : false;
}
/*
* Return "history" defined in PITCHME.yaml.
*/
public boolean fetchHistory() {
return (_yOpts != null) ? _yOpts.fetchHistory(params()) : false;
}
/*
* Return "slide-number" defined in PITCHME.yaml.
*/
public boolean fetchSlideNumber() {
return (_yOpts != null) ? _yOpts.fetchSlideNumber(params()) : false;
}
/*
* Return "mathjax" defined in PITCHME.yaml.
*/
public String fetchMathConfig() {
return (_yOpts != null) ? _yOpts.mathConfig(params()) :
YAMLOptions.MATHJAX_DEFAULT;
}
/*
* Return active theme.css for slideshow.
*/
public String fetchHighlightCSS() {
if (_yOpts != null) {
return _yOpts.fetchHighlight(params());
} else {
return _pp.darkTheme() ?
YAMLOptions.HIGHLIGHT_DARK_DEFAULT :
YAMLOptions.HIGHLIGHT_LIGHT_DEFAULT;
}
}
/*
* Return true if "published" set to true in PITCHME.yaml.
*/
public boolean published() {
return (_yOpts != null) ? _yOpts.published(_pp) : false;
}
public String fetchHorzDelim() {
String delim = null;
if(_yOpts != null && _yOpts.hasHorzDelim(params())) {
String regexp = _yOpts.fetchHorzDelimRegExp(params());
delim = (regexp != null) ? buildSlideDelim(regexp) :
buildSlideDelim(_yOpts.fetchHorzDelim(params()));
log.debug("fetchHorzDelim: custom delim={}", delim);
}
if(delim == null) {
if(MarkdownModel.HSLIDE_REGEX_DEFAULT != null)
delim = buildSlideDelim(MarkdownModel.HSLIDE_REGEX_DEFAULT);
else
delim = buildSlideDelim(MarkdownModel.HSLIDE_DELIM_DEFAULT);
}
return delim;
}
public String fetchVertDelim() {
String delim = null;
if(_yOpts != null && _yOpts.hasVertDelim(params())) {
String regexp = _yOpts.fetchVertDelimRegExp(params());
log.debug("fetchVertDelim: regexp={}", regexp);
delim = (regexp != null) ? buildSlideDelim(regexp) :
buildSlideDelim(_yOpts.fetchVertDelim(params()));
log.debug("fetchVertDelim: custom delim={}", delim);
}
if(delim == null) {
if(MarkdownModel.VSLIDE_REGEX_DEFAULT != null)
delim = buildSlideDelim(MarkdownModel.VSLIDE_REGEX_DEFAULT);
else
delim = buildSlideDelim(MarkdownModel.VSLIDE_DELIM_DEFAULT);
}
return delim;
}
/*
* Return true if "gatoken" defined in PITCHME.yaml.
*/
public boolean hasGAToken() {
return (_yOpts != null) ? _yOpts.hasGAToken(params()) : false;
}
/*
* Return "gatoken" defined in PITCHME.yaml.
*/
public String fetchGAToken() {
return (_yOpts != null) ?
_yOpts.fetchGAToken(params()) : null;
}
/*
* Return "revealjs-version" override for slideshow.
*/
public String fetchRevealVersionOverride() {
return (_yOpts != null) ?
_yOpts.fetchRevealVersion(params()) : null;
}
/*
* Return presentation Help message.
*/
public String fetchHelp(boolean smallScreen) {
return smallScreen ? SMALL_HELP : HELP;
}
public String toString() {
return _pretty;
}
public String key() {
return _cacheKey;
}
public String homePanel() {
return com.gitpitch.controllers.routes.PitchController.home(_pp.grs,
_pp.user,
_pp.repo,
_pp.branch,
_pp.theme,
_pp.pitchme,
"false").toString();
}
public String gitPanel() {
return com.gitpitch.controllers.routes.PitchController.git(_pp.grs,
_pp.user,
_pp.repo,
_pp.branch,
_pp.theme,
_pp.pitchme,
null).toString();
}
public String themesPanel() {
return com.gitpitch.controllers.routes.PitchController.themes(_pp.grs,
_pp.user,
_pp.repo,
_pp.branch,
_pp.theme,
_pp.pitchme,
null).toString();
}
private String buildSlideDelim(String pattern) {
log.debug("buildSlideDelim: pattern={}", pattern);
return new StringBuffer("(^").append(pattern)
.append("$|^")
.append(pattern)
.append("\\?.*)")
.toString();
}
private static final String SLASH = "/";
private static final String PARAM_BRANCH = "?b=";
private static final String PARAM_PITCHME = "&p=";
private static final String PITCHME_YAML = "PITCHME.yaml";
/*
* Model prefix identifier for cache key generator.
*/
private static final String MODEL_ID = "SSM:";
private static final Integer DEFAULT_PREV_KEYCODE = 37;
private static final Integer DEFAULT_NEXT_KEYCODE = 39;
private static final String THEME_FONT_DEFAULT =
"Source Sans Pro, Helvetica, sans-serif";
private static final String THEME_DARK_COLOR_INVERSE = "white";
private static final String THEME_LIGHT_COLOR_INVERSE = "black";
private static Map<String, String> THEME_FONTS =
Collections.unmodifiableMap(new HashMap<String, String>() {
{
put("black", "Source Sans Pro, Helvetica, sans-serif");
put("moon", "Lato, sans-serif");
put("night", "Open Sans, sans-serif");
put("beige", "Lato, sans-serif");
put("sky", "Open Sans, sans-serif");
put("white", "Source Sans Pro, Helvetica, sans-serif");
}
});
private static Map<String, String> LOGO_POSITIONS =
Collections.unmodifiableMap(new HashMap<String, String>() {
{
put("top-left", "position: fixed; top: 20px; left: 20px; z-index: 1");
put("top-right", "position: fixed; top: 20px; right: 20px; z-index: 1");
put("bottom-left", "position: fixed; bottom: 20px; left: 20px; z-index: 1");
put("bottom-right", "position: fixed; bottom: 20px; right: 20px; z-index: 1");
}
});
private static final String HELP =
"Navigate : Space / Arrow Keys | " +
"<a href='#' onclick='RevealMenu.toggle()'>M</a> - Menu | " +
"<a href='#' onclick='enterFullscreen()'>F</a> - Fullscreen | " +
"<a href='#' onclick='enterOverview()'>O</a> - Overview | " +
"<a href='#' onclick='enterBlackout()'>B</a> - Blackout | " +
"<a href='#' onclick='RevealNotes.open()'>S</a> - Speaker | " +
"<a href='#' onclick='enterHelp()'>?</a> - Help";
private static final String SMALL_HELP =
"<a href='#' onclick='RevealMenu.toggle()'>Menu</a> | " +
"<a href='#' onclick='enterFullscreen()'>Fullscreen</a> | " +
"<a href='#' onclick='enterOverview()'>Overview</a> | " +
"<a href='#' onclick='enterBlackout()'>Blackout</a> | " +
"<a href='#' onclick='RevealNotes.open()'>Speaker</a> | " +
"<a href='#' onclick='enterHelp()'>Help</a>";
}

View File

@ -1,179 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2017 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.oembed;
import com.gitpitch.utils.PitchLink;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.git.GRSManager;
import com.gitpitch.git.GRSService;
/*
* GitPitch oEmbed Provider.
*
* https://oembed.com
*/
public class PitchEmbed {
public String title;
public String author_name;
public String html;
public String type = TYPE;
public String version = VERSION;
public String provider_name = GITPITCH;
public String provider_url = GITPITCH_URL;
public String cache_age = CACHE;
public String width = DEFAULT_WIDTH;
public String height = DEFAULT_HEIGHT;
public String author_url;
public String thumbnail_url = DEFAULT_THUMB;
public String thumbnail_width;
public String thumbnail_height;
public static PitchEmbed build(GRSManager grsManager,
String url) {
return build(grsManager,
url,
DEFAULT_WIDTH,
DEFAULT_HEIGHT,
null, null);
}
public static PitchEmbed build(GRSManager grsManager,
String url,
String width,
String height,
String maxWidth,
String maxHeight) {
PitchLink pl = PitchLink.build(url);
PitchParams pp = PitchParams.build(pl.grs, pl.user, pl.repo, pl.branch);
String authorUrl = grsManager.get(pp).getSite();
authorUrl = new StringBuffer(authorUrl).append(pp.user)
.append(SLASH)
.append(pp.repo)
.toString();
return new PitchEmbed(pp,
pl,
authorUrl,
width,
height,
maxWidth,
maxHeight);
}
private PitchEmbed(PitchParams pp,
PitchLink pl,
String authorUrl,
String width,
String height,
String maxWidth,
String maxHeight) {
this.title = buildTitle(pp);
this.author_name = pl.user;
this.author_url = authorUrl;
this.width = buildWidth(width, maxWidth, maxHeight);
this.height = buildHeight(height, maxWidth, maxHeight);
this.thumbnail_width = this.width;
this.thumbnail_height = this.height;
this.html = buildHTML(pl.url, this.width, this.height);
}
private String buildTitle(PitchParams pp) {
return GITPITCH_PRESENTS + pp.pretty().substring(1);
}
private String buildWidth(String width,
String maxWidth,
String maxHeight) {
if(maxWidth != null)
return maxWidth;
if(maxHeight != null) {
try {
/*
* Maintain aspect ratio [ 1.38 : 1 ] [ 960px : 700px ].
*/
int maxH = Integer.parseInt(maxHeight);
return String.valueOf((int) Math.round(maxH * 1.38));
} catch(Exception ex) {}
}
return (width != null) ? width : DEFAULT_WIDTH;
}
private String buildHeight(String height,
String maxWidth,
String maxHeight) {
if(maxHeight != null)
return maxHeight;
if(maxWidth != null) {
try {
/*
* Maintain aspect ratio [ 1 : 0.73 ] [ 960px : 700px ].
*/
int maxW = Integer.parseInt(maxWidth);
return String.valueOf((int) Math.round(maxW * 0.73));
} catch(Exception ex) {}
}
return (height != null) ? height : DEFAULT_HEIGHT;
}
private String buildHTML(String url, String width, String height) {
return new StringBuffer(HTML_OPEN).append(HTML_WIDTH)
.append(width)
.append(HTML_HEIGHT)
.append(height)
.append(HTML_SRC)
.append(url)
.append(HTML_BORDER)
.append(HTML_MARGINS)
.append(HTML_SCROLL)
.append(HTML_CLOSE)
.toString();
}
private final static String GITPITCH = "GitPitch";
private final static String GITPITCH_PRESENTS = "GitPitch Presents: ";
private final static String GITPITCH_URL = "https://gitpitch.com";
private final static String TYPE = "rich";
private final static String VERSION = "1.0";
private final static String CACHE = "180";
private final static String DEFAULT_WIDTH = "960";
private final static String DEFAULT_HEIGHT = "700";
private final static String DEFAULT_THUMB =
"https://gitpitch.com/gitpitch-icon-black.jpg";
private final static String HTML_OPEN = "<iframe ";
private final static String HTML_WIDTH = "width=\"";
private final static String HTML_HEIGHT = "\" height=\"";
private final static String HTML_SRC = "\" src=\"";
private final static String HTML_BORDER = "\" frameborder=\"0\" ";
private final static String HTML_MARGINS =
"marginwidth=\"0\" marginheight=\"0\" ";
private final static String HTML_SCROLL = "scrolling=\"no\"";
private final static String HTML_CLOSE = " allowfullscreen></iframe>";
private final static String SLASH = "/";
}

View File

@ -1,117 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.policies;
import com.gitpitch.utils.PitchParams;
import javax.inject.*;
/*
* GitPitch Cache Timeout Policies.
*
* Content in master is considered stable so typically
* uses longer timeouts. Content in feature branches is
* considered under development so shorter timeouts
* are used to ensure changes are reflected quickly.
*/
@Singleton
public class CacheTimeout {
/*
* Return cache timeout in seconds for GitRepoModel.
*/
public int grm(PitchParams pp) {
if (pp.isLongLived()) {
return pp.isMaster() ? LL_MASTER_TIMEOUT : LL_BRANCH_TIMEOUT;
} else {
return pp.isMaster() ? GRM_MASTER_TIMEOUT : GRM_BRANCH_TIMEOUT;
}
}
/*
* Return cache timeout in seconds for SlideshowModel.
*/
public int ssm(PitchParams pp) {
if (pp.isLongLived()) {
return pp.isMaster() ? LL_MASTER_TIMEOUT : LL_BRANCH_TIMEOUT;
} else {
return pp.isMaster() ? SSM_MASTER_TIMEOUT : SSM_BRANCH_TIMEOUT;
}
}
/*
* Return cache timeout in seconds for MarkdownModel.
*/
public int mdm(PitchParams pp) {
if (pp.isLongLived()) {
return pp.isMaster() ? LL_MASTER_TIMEOUT : LL_BRANCH_TIMEOUT;
} else {
return pp.isMaster() ? MDM_MASTER_TIMEOUT : MDM_BRANCH_TIMEOUT;
}
}
/*
* Return cache timeout in milliseconds for print PDF file.
*/
public long pdf(PitchParams pp) {
return pp.isMaster() ? PDF_CACHE_MAX_AGE_MASTER : PDF_CACHE_MAX_AGE_BRANCH;
}
/*
* Return cache timeout in milliseconds for offline ZIP file.
*/
public long zip(PitchParams pp) {
return pp.isMaster() ? ZIP_CACHE_MAX_AGE_MASTER : ZIP_CACHE_MAX_AGE_BRANCH;
}
/*
* PDF generation cache timeouts (ms) for PITCHME.pdf.
*/
public static final long PDF_CACHE_MAX_AGE_MASTER = 60 * 1000 * 20;
public static final long PDF_CACHE_MAX_AGE_BRANCH = 20 * 1000;
/*
* Offline generation cache timeouts (ms) for PITCHME.zip.
*/
public static final long ZIP_CACHE_MAX_AGE_MASTER = 60 * 1000 * 20;
public static final long ZIP_CACHE_MAX_AGE_BRANCH = 20 * 1000;
/*
* Long Lived cache timeouts (sec) for GitPitch-owned repos.
*/
private static final int LL_MASTER_TIMEOUT = 60 * 60;
private static final int LL_BRANCH_TIMEOUT = 15;
/*
* GitRepoModel cache timeouts (sec) for GitHub repo meta-data.
*/
private static final int GRM_MASTER_TIMEOUT = 60 * 30;
private static final int GRM_BRANCH_TIMEOUT = 60 * 30;
/*
* SlideshowModel cache timeouts (sec) for PITCHME.[css|jpg].
*/
private static final int SSM_MASTER_TIMEOUT = 15;
private static final int SSM_BRANCH_TIMEOUT = 15;
/*
* MarkdownModel cache timeouts (sec) for PITCHME.md.
*/
private static final int MDM_MASTER_TIMEOUT = SSM_MASTER_TIMEOUT;
private static final int MDM_BRANCH_TIMEOUT = SSM_BRANCH_TIMEOUT;
}

View File

@ -1,123 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.policies;
import com.gitpitch.policies.Runtime;
import javax.inject.*;
/*
* External dependency manager for the GitPitch server.
*/
@Singleton
public final class Dependencies {
private final Runtime runtime;
private final String cdn;
private final String revealjsVersion;
private final String bootstrapVersion;
private final String jqueryVersion;
private final String fontawesomeVersion;
private final String octiconsVersion;
private final String highlightjsVersion;
private final Boolean highlightPluginEnabled;
@Inject
public Dependencies(Runtime runtime) {
this.runtime = runtime;
this.cdn = runtime.config("gitpitch.dependency.cdn");
this.revealjsVersion = runtime.config("gitpitch.dependency.revealjs");
this.bootstrapVersion = runtime.config("gitpitch.dependency.bootstrap");
this.jqueryVersion = runtime.config("gitpitch.dependency.jquery");
this.fontawesomeVersion = runtime.config("gitpitch.dependency.fontawesome");
this.octiconsVersion = runtime.config("gitpitch.dependency.octicons");
this.highlightjsVersion = runtime.config("gitpitch.dependency.highlightjs");
this.highlightPluginEnabled =
runtime.configBool("gitpitch.dependency.highlight.plugin", false);
}
public String revealjs(boolean offline, String versionOverride) {
return build(offline, REVEALJS, (versionOverride != null) ?
versionOverride : revealjsVersion);
}
public String bootstrap(boolean offline) {
return build(offline, BOOTSTRAP, bootstrapVersion);
}
public String jquery(boolean offline) {
return build(offline, JQUERY, jqueryVersion);
}
public String fontawesome(boolean offline) {
return build(offline, FONTAWE, fontawesomeVersion);
}
public String octicons(boolean offline) {
return build(offline, OCTICONS, octiconsVersion);
}
public String highlightjs(boolean offline) {
return build(offline, HIGHLIGHT, highlightjsVersion);
}
public String gitpitchjs(boolean offline) {
return build(offline, GIPITCHJS);
}
public String gitpitchimg(boolean offline) {
return build(offline, GIPITCHIMG);
}
public Boolean highlightPluginEnabled() {
return highlightPluginEnabled;
}
public Boolean cdnDisabled() {
return cdn == null;
}
private String build(boolean offline, String libName) {
if(offline) {
return "./assets" + libName;
} else {
return (cdn != null) ? (cdn + libName) : (DEFAULT_CDN + libName);
}
}
private String build(boolean offline, String libName, String libVersion) {
return build(offline, libName) + libVersion;
}
private static final String GIPITCHJS = "/js";
private static final String GIPITCHIMG = "/img";
private static final String REVEALJS = "/reveal.js/";
private static final String BOOTSTRAP = "/bootstrap/";
private static final String JQUERY = "/jquery/";
private static final String FONTAWE = "/font-awesome/";
private static final String OCTICONS = "/octicons/";
private static final String HIGHLIGHT = "/highlight.js/";
private static final String DEFAULT_CDN = "/assets/libs";
}

View File

@ -1,71 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.policies;
import play.Configuration;
import play.Environment;
import java.util.List;
import javax.inject.*;
/*
* External dependency manager for the GitPitch server.
*/
@Singleton
public final class Runtime {
private final Configuration cfg;
private final Environment env;
@Inject
public Runtime(Configuration cfg,
Environment env) {
this.cfg = cfg;
this.env = env;
}
public String config(String cid) {
return cfg.getString(cid);
}
public List configList(String cid) {
return cfg.getList(cid);
}
public List configStringList(String cid) {
return cfg.getStringList(cid);
}
public boolean configBool(String cid) {
return cfg.getBoolean(cid);
}
public boolean configBool(String cid, boolean defaultCfg) {
return cfg.getBoolean(cid, defaultCfg);
}
public boolean isProd() {
return env.isProd();
}
}

View File

@ -1,184 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.git.GRS;
import com.gitpitch.git.GRSService;
import com.gitpitch.git.GRSManager;
import com.gitpitch.services.DiskService;
import com.gitpitch.services.SlideService;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.DelimParams;
import com.gitpitch.utils.YAMLOptions;
import java.util.*;
import java.nio.file.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md code support service.
*/
@Singleton
public class CodeService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final GRSManager grsManager;
private final DiskService diskService;
private final SlideService slideService;
@Inject
public CodeService(GRSManager grsManager,
DiskService diskService,
SlideService slideService) {
this.grsManager = grsManager;
this.diskService = diskService;
this.slideService = slideService;
}
public String build(String md,
DelimParams dp,
PitchParams pp,
YAMLOptions yOpts,
MarkdownModel mdm) {
String codeBlock = mdm.extractDelim(md);
try {
String codePath = dp.get(MarkdownModel.DELIM_QUERY_CODE);
String langHint = dp.get(MarkdownModel.DELIM_QUERY_LANG);
String slideTitle = dp.get(MarkdownModel.DELIM_QUERY_TITLE);
GRS grs = grsManager.get(pp);
GRSService grsService = grsManager.getService(grs);
int downStatus =
grsService.download(pp, SOURCE_CODE, codePath);
String theStructure = slideService.build(md, dp, pp, yOpts, mdm);
String theContent = null;
if(downStatus == 0) {
String code = diskService.asText(pp, SOURCE_CODE);
if(isMarkdown(codePath, langHint)) {
code = prepMarkdown(code);
}
theContent = buildCodeBlock(mdm.extractDelim(md),
code, langHint, slideTitle);
} else {
theContent = buildCodeBlockError(mdm.extractDelim(md), codePath);
}
return new StringBuffer(theStructure).append(theContent)
.toString();
} catch (Exception ex) {
log.warn("build: ex={}", ex);
}
return codeBlock;
}
private String buildCodeBlock(String delim,
String code,
String langHint,
String slideTitle) {
StringBuffer slide = new StringBuffer();
if(slideTitle != null) {
slide = slide.append(MarkdownModel.MD_SPACER)
.append("<span class='menu-title slide-title'>")
.append(slideTitle)
.append("</span>")
.append(MarkdownModel.MD_SPACER);
}
slide = slide.append(MarkdownModel.MD_CODE_BLOCK_OPEN);
if(langHint != null) {
slide = slide.append(langHint);
}
return slide.append(MarkdownModel.MD_SPACER)
.append(code)
.append(MarkdownModel.MD_SPACER)
.append(MarkdownModel.MD_CODE_BLOCK_CLOSE)
.append(MarkdownModel.MD_SPACER)
.toString();
}
private String buildCodeBlockError(String delim, String codePath) {
return new StringBuffer(SOURCE_CODE_DELIMITER)
.append(MarkdownModel.MD_SPACER)
.append(codePath)
.append(MarkdownModel.MD_SPACER)
.append(SOURCE_CODE_NOT_FOUND)
.append(MarkdownModel.MD_SPACER)
.toString();
}
private boolean isMarkdown(String codePath, String langHint) {
return ((codePath != null) && codePath.endsWith(MARKDOWN_EXTENSION)) ||
(langHint != null && langHint.toLowerCase().equals("markdown"));
}
/*
* To prevent MD code being treated as presentation content
* do the following on code-delimiter injection:
*
* 1. Auto-indent code.
* 2. Replace inline code block tripple-ticks with double-ticks
* to prevent nested code-block parser and rendering errors.
*/
private String prepMarkdown(String md) {
try {
md = Stream.of(lineByLine(md)).map(mdline -> {
return mdline.startsWith(MARKDOWN_CODE_TICKS) ?
mdline.substring(1) : mdline;
}).map(mdline -> {
return MARKDOWN_INDENT + mdline;
}).collect(Collectors.joining(MarkdownModel.MD_SPACER));
} catch(Exception ex) {}
return md;
}
private String[] lineByLine(String md) {
return md.split("\\r?\\n");
}
private static final String SOURCE_CODE = "PITCHME.code";
private static final String SOURCE_CODE_DELIMITER =
"### Code Block Delimiter";
private static final String SOURCE_CODE_NOT_FOUND =
"### Source File Not Found";
private static final String MARKDOWN_EXTENSION = ".md";
private static final String MARKDOWN_INDENT = " ";
private static final String MARKDOWN_NEWLINE = "\n";
private static final String MARKDOWN_CODE_TICKS = "```";
}

View File

@ -1,227 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.git.GRS;
import com.gitpitch.git.GRSService;
import com.gitpitch.services.WebService;
import com.gitpitch.models.MarkdownModel;
import play.Logger;
import javax.inject.*;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Arrays;
import java.util.List;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* Composable service supporting Markdown includes in
* the form of:
*
* ---?include=/path/to/some.md
* +++?include=/path/to/other.md
*/
@Singleton
public class ComposableService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final DiskService ds;
private final WebService ws;
@Inject
public ComposableService(DiskService ds,
WebService ws) {
this.ds = ds;
this.ws = ws;
}
/*
* Make best effort to process composable presentation
* includes within PITCHME.md.
*/
public void compose(PitchParams pp,
GRS grs,
GRSService grsService) {
try {
Path mdPath = ds.asPath(pp, PitchParams.PITCHME_MD);
String composed = null;
try (Stream<String> stream = Files.lines(mdPath)) {
composed = stream.map(md -> {
if(md.startsWith(HSLIDE_INCLUDE)) {
String included = handleInclude(pp,
md,
HSLIDE_INCLUDE,
grsService,
grs.getHeaders());
if(included != null) {
return MarkdownModel.HSLIDE_DELIM_DEFAULT +
NEWLINES + included;
} else {
return notFound(MarkdownModel.HSLIDE_DELIM_DEFAULT,
includePath(md, HSLIDE_INCLUDE));
}
} else
if(md.startsWith(VSLIDE_INCLUDE)) {
String included = handleInclude(pp,
md,
VSLIDE_INCLUDE,
grsService,
grs.getHeaders());
if(included != null) {
return MarkdownModel.VSLIDE_DELIM_DEFAULT +
NEWLINES + included;
} else {
return notFound(MarkdownModel.VSLIDE_DELIM_DEFAULT,
includePath(md, VSLIDE_INCLUDE));
}
} else {
return md;
}
}).collect(Collectors.joining("\n"));
boolean overwritten = overwrite(pp, mdPath, composed);
log.debug("compose: overwritten md={}", overwritten);
} catch (Exception mex) {
log.warn("Markdown processing ex={}", mex);
composed = "PITCHME.md could not be parsed.";
}
} catch(Exception stex) {
}
}
private String handleInclude(PitchParams pp,
String md,
String includeDelim,
GRSService grsService,
Map<String,String> headers) {
String included = null;
String includePath = includePath(md, includeDelim);
if(FORBIDDEN.contains(includePath)) {
included = notPermitted(includeDelim, includePath);
} else {
included = fetchInclude(pp, includePath,
includeDelim, grsService, headers);
}
return included;
}
private String fetchInclude(PitchParams pp,
String includePath,
String includeDelim,
GRSService grsService,
Map<String,String> headers) {
String fetched = null;
try {
if(!isAbsolute(includePath))
includePath = grsService.raw(pp, includePath, true);
fetched = ws.fetchText(pp, includePath, headers);
} catch(Exception fiex) {
log.warn("fetchInclude: pp={}, error={}", pp, fiex);
}
return fetched;
}
private String includePath(String md, String includeDelim) {
try {
return md.substring(includeDelim.length());
} catch(Exception ipex) {
return md;
}
}
private boolean overwrite(PitchParams pp,
Path mdPath,
String stitched) {
try {
Files.write(mdPath, stitched.getBytes(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING );
return true;
} catch(Exception fex) {
log.warn("overwrite: pp={}, write error={}", pp, fex);
return false;
}
}
private String notFound(String delim, String path) {
StringBuffer buf = new StringBuffer(delim);
buf.append(NEWLINES)
.append("### GitPitch ?Include")
.append(NEWLINES).append(".").append(NEWLINES)
.append(path)
.append(NEWLINES).append(".").append(NEWLINES)
.append("Markdown File Not Found");
return buf.toString();
}
private String notPermitted(String delim, String path) {
StringBuffer buf = new StringBuffer(NEWLINES);
buf.append("### GitPitch ?Include")
.append(NEWLINES).append(".").append(NEWLINES)
.append(path)
.append(NEWLINES).append(".").append(NEWLINES)
.append("Path Not Permitted");
return buf.toString();
}
private boolean isAbsolute(String path) {
return path.startsWith(HTTP);
}
public final String HSLIDE_INCLUDE =
MarkdownModel.HSLIDE_DELIM_DEFAULT + "?include=";
public final String VSLIDE_INCLUDE =
MarkdownModel.VSLIDE_DELIM_DEFAULT + "?include=";
private final String HTTP = "http";
private final String NEWLINES = "\n\n";
private final List<String> FORBIDDEN =
Arrays.asList(PitchParams.PITCHME_MD, "./PITCHME.md");
}

View File

@ -1,288 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.git.GRS;
import com.gitpitch.git.GRSService;
import com.gitpitch.git.GRSManager;
import com.gitpitch.services.WebService;
import com.gitpitch.policies.Runtime;
import com.gitpitch.utils.PitchParams;
import org.apache.commons.io.FileUtils;
import play.Logger;
import javax.inject.*;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Map;
/*
* File system storage service.
*/
@Singleton
public class DiskService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final String storage;
private final String decktape;
private final ShellService shellService;
private final Runtime runtime;
private final WebService ws;
@Inject
public DiskService(ShellService shellService,
Runtime runtime,
WebService ws) {
this.shellService = shellService;
this.runtime = runtime;
this.ws = ws;
this.storage = runtime.config("gitpitch.storage.home");
this.decktape = runtime.config("gitpitch.decktape.home");
}
/*
* Return PitchParams branch working directory.
*/
public Path bwd(PitchParams pp) {
return Paths.get(storage(), pp.grs, pp.user, pp.repo, pp.branch);
}
/*
* Return Path for file within PitchParams branch working directory.
*/
public Path asPath(PitchParams pp,
String filename) {
return Paths.get(storage(), pp.grs, pp.user, pp.repo, pp.branch, filename);
}
/*
* Return File for file within PitchParams branch working directory.
*/
public File asFile(PitchParams pp,
String filename) {
return asPath(pp, filename).toFile();
}
/*
* Return text contents for file within PitchParams branch working directory.
*/
public String asText(PitchParams pp,
String filename) {
String text = "";
try {
Path filePath = asPath(pp, filename);
text = new String(Files.readAllBytes(filePath));
} catch(Exception tex) {}
return text;
}
/*
* Ensure PitchParams branch working directory exists.
*/
public Path ensure(PitchParams pp) {
return ensure(bwd(pp));
}
/*
* Ensure PitchParams branch working sub-directory exists.
*/
public Path ensure(PitchParams pp, String subdir) {
return (subdir != null) ?
ensure(asPath(pp, subdir)) : ensure(bwd(pp));
}
/*
* Ensure PitchParams branch working directory exists.
*/
public Path ensure(Path dirPath) {
try {
Files.createDirectories(dirPath);
} catch (Exception ex) {
}
return dirPath;
}
/*
* Download file from source into bwd resulting in dest.
*/
public int download(PitchParams pp,
Path wd,
String source,
String dest,
Map<String,String> headers) {
int downloaded = 999;
try {
log.debug("download: pp={}, source={}", pp, source);
ensure(bwd(pp));
Path destPath = Paths.get(wd.toString(), dest);
delete(destPath);
final long start = System.currentTimeMillis();
byte[] fetched = ws.fetchBytes(pp, source, headers);
if (fetched != null) {
Files.write(destPath, fetched);
downloaded = STATUS_OK;
log.debug("download: pp={}, time-taken={} (ms) to " +
"write {} bytes to {} from source={}", pp,
(System.currentTimeMillis() - start),
fetched.length, destPath, source);
} else {
log.warn("download: pp={}, failed to download and write " +
"from source={}", pp, source);
}
} catch(Exception dex) {
log.warn("download: failed pp={}, from source={}, ex={}",
pp, source, dex);
}
return downloaded;
}
public void copyDirectoryFromJar(Path jarPath, String jarDir, Path dest) {
log.debug("copyDirectoryFromJar: jarPath={}, jarDir={}, dest={}",
jarPath, jarDir, dest);
try(FileSystem fs = FileSystems.newFileSystem(jarPath, null)) {
final Path source = fs.getPath(jarDir);
copyDirectory(source, dest);
} catch(Exception cex) {
log.warn("copyDirectoryFromJar: jarPath={}, jarDir={}, dest={}, ex={}",
jarPath, jarDir, dest, cex);
}
}
public void copyDirectory(Path source, Path dest) {
log.debug("copyDirectory: source={}, dest={}", source, dest);
try {
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
Path relative = source.relativize(dir);
Path visitPath =
Paths.get(dest.toString(), relative.toString());
ensure(visitPath);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
Path copyTarget = Paths.get(dest.toString(),
source.relativize(file).toString());
if(!file.getFileName().toString().matches("\\..*") &&
!copyTarget.getFileName().toString().matches("\\..*")) {
Files.copy(file, copyTarget);
}
return FileVisitResult.CONTINUE;
}
});
} catch(Exception cex) {
log.warn("copyDirectory: source={}, dest={}, ex={}", source, dest, cex);
}
}
/*
* Delete file within PitchParams working directory.
*/
public void delete(PitchParams pp,
String filename) {
delete(asPath(pp, filename));
}
/*
* Recursively delete a target directory and contents.
*/
public void deepDelete(PitchParams pp, String target) {
Path branchPath = asPath(pp, target);
deepDelete(branchPath.toFile());
}
/*
* Recursively delete a target directory and contents.
*/
public void deepDelete(File directory) {
try {
if(directory.exists()) {
FileUtils.deleteDirectory(directory);
}
} catch (IOException ioex) {
log.warn("deepDelete: {}, ex={}", directory, ioex);
}
}
/*
* Delete file within PitchParams working directory.
*/
public void delete(Path filePath) {
try {
Files.deleteIfExists(filePath);
} catch (Exception dex) {
}
}
/*
* Return disk storage home directory.
*/
public String storage() {
return storage;
}
/*
* Return DeckTape PDF Exporter home directory.
*/
public String decktape() {
return decktape;
}
private static final Integer STATUS_OK = 0;
}

View File

@ -1,241 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.services.DiskService;
import com.gitpitch.services.SlideService;
import com.gitpitch.git.GRS;
import com.gitpitch.git.GRSService;
import com.gitpitch.git.GRSManager;
import com.gitpitch.git.vendors.GitHub;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.DelimParams;
import com.gitpitch.utils.YAMLOptions;
import java.util.*;
import java.nio.file.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md GIST support service.
*/
@Singleton
public class GISTService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final GRSManager grsManager;
private final DiskService diskService;
private final SlideService slideService;
@Inject
public GISTService(GRSManager grsManager,
DiskService diskService,
SlideService slideService) {
this.grsManager = grsManager;
this.diskService = diskService;
this.slideService = slideService;
}
public String build(String md,
DelimParams dp,
PitchParams pp,
YAMLOptions yOpts,
MarkdownModel mdm) {
try {
String gid = dp.get(MarkdownModel.DELIM_QUERY_GIST);
if(backCompat(gid)) {
return buildBackCompat(md, dp, pp, yOpts, mdm);
} else {
String fileHint = dp.get(MarkdownModel.DELIM_QUERY_FILE);
String langHint = dp.get(MarkdownModel.DELIM_QUERY_LANG);
String slideTitle = dp.get(MarkdownModel.DELIM_QUERY_TITLE);
String extractedDelim = mdm.extractDelim(md);
/*
* GIST is a GitHub specific service so override
* active-GRS to ensure communiction with GitHub.
*/
GRS grs = grsManager.get(GitHub.TYPE);
GRSService grsService = grsManager.getService(grs);
Path branchPath = diskService.ensure(pp);
String gistLink = grsService.gist(pp, gid, fileHint);
int downStatus =
diskService.download(pp, branchPath, gistLink,
GIST_CODE, grs.getHeaders());
String theStructure = slideService.build(md, dp, pp, yOpts, mdm);
String theContent = null;
if(downStatus == 0) {
String code = diskService.asText(pp, GIST_CODE);
theContent = buildCodeBlock(extractedDelim,
code, langHint, slideTitle);
} else {
theContent =
buildCodeBlockError(extractedDelim, gid, fileHint);
}
return new StringBuffer(theStructure).append(theContent)
.toString();
}
} catch (Exception ex) {
log.warn("build: ex={}", ex);
return slideService.build(md, dp, pp, yOpts, mdm);
}
}
public String offline() {
return new StringBuffer(OFFLINE_GIST).append(MarkdownModel.MD_SPACER)
.append(OFFLINE_NOTICE)
.toString();
}
private String buildCodeBlock(String delim,
String code,
String langHint,
String slideTitle) {
log.debug("buildCodeBlock: delim={}, langHint={}, slideTitle={}",
delim, langHint, slideTitle);
StringBuffer slide = new StringBuffer();
if(slideTitle != null) {
slide = slide.append(MarkdownModel.MD_SPACER)
.append("<span class='menu-title slide-title'>")
.append(slideTitle)
.append("</span>")
.append(MarkdownModel.MD_SPACER);
}
slide = slide.append(MarkdownModel.MD_CODE_BLOCK_OPEN);
if(langHint != null) {
slide = slide.append(langHint);
}
return slide.append(MarkdownModel.MD_SPACER)
.append(code)
.append(MarkdownModel.MD_SPACER)
.append(MarkdownModel.MD_CODE_BLOCK_CLOSE)
.append(MarkdownModel.MD_SPACER)
.toString();
}
private String buildCodeBlockError(String delim,
String codePath,
String fileHint) {
log.debug("buildCodeBlockError: delim={}, codePath={}, fileHint={}",
delim, codePath, fileHint);
String filePath = fileHint != null ? fileHint : GIST_DEFAULT_FILE;
filePath = "[ " + filePath + " ]";
return new StringBuffer(GIST_DELIMITER)
.append(MarkdownModel.MD_SPACER)
.append(codePath)
.append(MarkdownModel.MD_SPACER)
.append(filePath)
.append(MarkdownModel.MD_SPACER)
.append(GIST_NOT_FOUND)
.append(MarkdownModel.MD_SPACER)
.toString();
}
private boolean backCompat(String gid) {
return !gid.contains(GIST_ID_DELIM);
}
/*
* Provide backward compatible support for embedding
* GIST within an iframe. This approach has been superceded
* by injecting GIST source into code-blocks.
*/
private String buildBackCompat(String md,
DelimParams dp,
PitchParams pp,
YAMLOptions yOpts,
MarkdownModel mdm) {
try {
String gid = dp.get(MarkdownModel.DELIM_QUERY_GIST);
String gistCallback =
com.gitpitch.controllers.routes.PitchController.gist(gid)
.url();
String theStructure = slideService.build(md, dp, pp, yOpts, mdm);
return new StringBuffer(theStructure)
.append(GIST_DIV_OPEN)
.append(GIST_DIV_CLASS)
.append(GIST_IFR_OPEN)
.append(gistCallback)
.append(GIST_IFR_CLSE)
.append(GIST_DIV_CLSE)
.append(MarkdownModel.MD_SPACER)
.toString();
} catch (Exception ex) {
log.warn("buildBackCompat: ex={}", ex);
return slideService.build(md, dp, pp, yOpts, mdm);
}
}
private static final String GIST_CODE = "PITCHME.gist";
private static final String GIST_DELIMITER = "### GIST Delimiter";
private static final String GIST_NOT_FOUND = "### GIST Not Found";
private static final String GIST_ID_DELIM = "/";
private static final String GIST_DEFAULT_FILE = "Default File";
/*
* BackCompat GIST IFrame Frags (scrolling permitted).
*/
private static final String GIST_DIV_OPEN = "<div data-gist=\"true\" ";
private static final String GIST_DIV_CLASS = "class=\"stretch\">";
private static final String GIST_IFR_OPEN =
"<iframe width=\"100%\" height=\"100%\" src=\"";
private static final String GIST_IFR_CLSE =
"\" frameborder=\"0\" scrolling=\"yes\" allowfullscreen></iframe>";
private static final String GIST_DIV_CLSE = "</div>";
/*
* BackCompat Offline GIST Frags.
*/
private static final String OFFLINE_GIST = "#### GIST Slide Disabled";
private static final String OFFLINE_NOTICE = "#### [ GitPitch Offline ]";
}

View File

@ -1,435 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.fasterxml.jackson.databind.JsonNode;
import com.gitpitch.factory.MarkdownModelFactory;
import com.gitpitch.git.*;
import com.gitpitch.models.GitRepoModel;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.policies.CacheTimeout;
import com.gitpitch.executors.BackEndThreads;
import com.gitpitch.utils.*;
import play.Logger;
import play.cache.*;
import play.libs.ws.*;
import javax.inject.*;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/*
* GitHub API integration service.
*/
@Singleton
public class GitService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final ConcurrentHashMap<String, CountDownLatch> repoLatchMap =
new ConcurrentHashMap();
private final ConcurrentHashMap<String, CountDownLatch> yamlLatchMap =
new ConcurrentHashMap();
private final ConcurrentHashMap<String, CountDownLatch> markdownLatchMap =
new ConcurrentHashMap();
private final GRSManager grsManager;
private final DiskService diskService;
private final PrintService printService;
private final ShellService shellService;
private final CacheTimeout cacheTimeout;
private final BackEndThreads backEndThreads;
private final MarkdownModelFactory markdownModelFactory;
private final ComposableService composableService;
private final WSClient wsClient;
private final CacheApi pitchCache;
@Inject
public GitService(GRSManager grsManager,
DiskService diskService,
PrintService printService,
ShellService shellService,
CacheTimeout cacheTimeout,
BackEndThreads backEndThreads,
MarkdownModelFactory markdownModelFactory,
ComposableService composableService,
WSClient wsClient,
CacheApi pitchCache) {
this.grsManager = grsManager;
this.diskService = diskService;
this.printService = printService;
this.shellService = shellService;
this.cacheTimeout = cacheTimeout;
this.backEndThreads = backEndThreads;
this.markdownModelFactory = markdownModelFactory;
this.composableService = composableService;
this.wsClient = wsClient;
this.pitchCache = pitchCache;
}
/*
* Fetch GitHub repo meta-data on GitHub API.
*/
public CountDownLatch fetchRepo(PitchParams pp) {
final String grmKey = GitRepoModel.genKey(pp);
log.debug("fetchRepo: pp={}", pp);
CountDownLatch freshLatch = new CountDownLatch(1);
CountDownLatch activeLatch =
repoLatchMap.putIfAbsent(grmKey, freshLatch);
if (activeLatch != null) {
/*
* Non-null activeLatch implies a fetchRepo() operation
* is already in progress for this /{user}/{repo}. So
* activeLatch so caller can block until operation completes.
*/
log.debug("fetchRepo: pp={}, already in progress, " +
"returning existing activeLatch={}", pp, activeLatch);
return activeLatch;
} else {
GRS grs = grsManager.get(pp);
final GRSService grsService = grsManager.getService(grs);
String apiCall = grsService.repo(pp);
log.debug("fetchRepo: apiCall={}", apiCall);
final long start = System.currentTimeMillis();
WSRequest apiRequest = wsClient.url(apiCall);
grs.getHeaders().forEach((k,v) -> {
apiRequest.setHeader(k, v);
});
CompletableFuture<WSResponse> apiFuture =
apiRequest.get().toCompletableFuture();
CompletableFuture<GitRepoModel> rmFuture =
apiFuture.thenApplyAsync(apiResp -> {
log.debug("fetchRepo: pp={}, fetch meta time-taken={}",
pp, (System.currentTimeMillis() - start));
log.info("{}: API Rate Limit Status [ {}, {} ]",
grs.getName(),
apiResp.getHeader(API_RATE_LIMIT),
apiResp.getHeader(API_RATE_LIMIT_REMAINING));
try {
if (apiResp.getStatus() == HTTP_OK) {
try {
JsonNode json = apiResp.asJson();
GitRepoModel grm = grsService.model(pp, json);
/*
* Update pitchCache with new GitRepoModel
* generated using GitHub API response data.
*/
pitchCache.set(grm.key(), grm, cacheTimeout.grm(pp));
} catch (Exception ex) {
/*
* Prevent any runtime errors, such as JSON parsing,
* from propogating to the front end.
*/
log.warn("fetchRepo: pp={}, unexpected ex={}", pp, ex);
}
} else {
log.debug("fetchRepo: pp={}, fail status={}",
pp, apiResp.getStatus());
try {
String remainingHdr =
apiResp.getHeader(API_RATE_LIMIT_REMAINING);
int rateLimitRemaining =
Integer.parseInt(remainingHdr);
if (rateLimitRemaining <= 0) {
log.warn("WARNING! {} API rate limit exceeded.", grs.getName());
}
} catch (Exception rlex) {
}
}
} catch (Exception rex) {
log.warn("fetchRepo: pp={}, unexpected runtime ex={}", pp, rex);
}
/*
* Current operation completed, so remove latch associated
* with operation from repoLatchMap to permit future operations
* on this /{user}/{repo}.
*/
releaseCountDownLatch(repoLatchMap, grmKey);
/*
* Operation completed, valid result cached, no return required.
*/
return null;
}, backEndThreads.POOL)
.handle((result, error) -> {
if (error != null) {
log.warn("fetchRepo: pp={}, fetch error={}", pp, error);
releaseCountDownLatch(repoLatchMap, grmKey);
}
return null;
});
return freshLatch;
}
}
/*
* Fetch PITCHME.yaml configuration from GitHub repo.
*/
public CountDownLatch fetchYAML(PitchParams pp) {
final String ssmKey = SlideshowModel.genKey(pp);
CountDownLatch freshLatch = new CountDownLatch(1);
CountDownLatch activeLatch =
yamlLatchMap.putIfAbsent(ssmKey, freshLatch);
if (activeLatch != null) {
/*
* A non-null activeLatch implies a fetchYAML()
* operation is already in progress for the current
* /{user}/{repo}?b={branch}.
*/
log.debug("fetchYAML: pp={}, already in progress, " +
"returning existing activeLatch={}", pp, activeLatch);
return activeLatch;
} else {
CompletableFuture<Void> syncFuture =
CompletableFuture.supplyAsync(() -> {
GRS grs = grsManager.get(pp);
GRSService grsService = grsManager.getService(grs);
int downYAML = grsService.download(pp,
PitchParams.PITCHME_YAML, pp.YAML());
boolean downOk = downYAML == STATUS_OK;
log.debug("fetchYAML: pp={}, colocated YAML={}",
pp, downYAML);
/*
* If PITCHME.yaml not found at pp.pitchme path
* try locate file using GitPitch convention
* default by looking in repo root directory.
*/
if(!downOk && pp.pitchme != null) {
downYAML =
grsService.download(pp,
PitchParams.PITCHME_YAML,
PitchParams.PITCHME_YAML);
downOk = downYAML == STATUS_OK;
log.debug("fetchYAML: pp={}, fallback YAML={}",
pp, downYAML);
}
/*
* Update pitchCache with new SlideshowModel.
*/
SlideshowModel ssm =
SlideshowModel.build(pp, downOk, grsService, diskService);
pitchCache.set(ssm.key(), ssm, cacheTimeout.ssm(pp));
/*
* Current operation completed, so remove latch associated
* with operation from yamlLatchMap to permit future
* operations on this /{user}/{repo}?b={branch}.
*/
releaseCountDownLatch(yamlLatchMap, ssmKey);
/*
* Operation completed, valid result cached, no return required.
*/
return null;
}, backEndThreads.POOL)
.handle((result, error) -> {
if (error != null) {
log.warn("fetchYAML: pp={}, fetch error={}", pp, error);
releaseCountDownLatch(yamlLatchMap, ssmKey);
}
return null;
});
return freshLatch;
}
}
/*
* Fetch PITCHME.md markdown from GitHub repo.
*/
public CountDownLatch fetchMarkdown(PitchParams pp) {
final String mdmKey = MarkdownModel.genKey(pp);
CountDownLatch freshLatch = new CountDownLatch(1);
CountDownLatch activeLatch =
markdownLatchMap.putIfAbsent(mdmKey, freshLatch);
if (activeLatch != null) {
/*
* A non-null activeLatch implies a fetchMarkdown()
* operation is already in progress for the current
* /{user}/{repo}?b={branch}.
*/
log.debug("fetchMarkdown: pp={}, already in progress, " +
"returning existing activeLatch={}", pp, activeLatch);
return activeLatch;
} else {
CompletableFuture<Void> syncFuture =
CompletableFuture.supplyAsync(() -> {
GRS grs = grsManager.get(pp);
GRSService grsService = grsManager.getService(grs);
int downStatus = grsService.download(pp,
PitchParams.PITCHME_MD, pp.MD());
if (downStatus == STATUS_OK) {
/*
* Process Composable Presentation includes
* found within PITCHME.md.
*/
composableService.compose(pp, grs, grsService);
String ssmKey = SlideshowModel.genKey(pp);
Optional<SlideshowModel> ssmo =
Optional.ofNullable(pitchCache.get(ssmKey));
/*
* The SSM in the pitchCache can be absent if
* we are currently processing a print or offline
* download. In these caes, quickly reconstitute
* the SSM using YAML on disk so markdown rendering
* can honor all custom YAML configurations.
*/
if(!ssmo.isPresent()) {
SlideshowModel ssm =
SlideshowModel.build(pp, true, grsService, diskService);
ssmo = Optional.of(ssm);
}
MarkdownRenderer mrndr = MarkdownRenderer.build(pp,
ssmo, grsService, diskService);
// MarkdownModel mdm = MarkdownModel.consume(mrndr);
MarkdownModel mdm =
(MarkdownModel) markdownModelFactory.create(mrndr);
pitchCache.set(mdmKey, mdm, cacheTimeout.mdm(pp));
} else {
log.debug("fetchMarkdown: pp={}, failed status={}",
pp, downStatus);
}
/*
* Current operation completed, so remove latch associated
* with operation from markdownLatchMap to permit future
* operations on this /{user}/{repo}?b={branch}.
*/
releaseCountDownLatch(markdownLatchMap, mdmKey);
/*
* Operation completed, valid result cached, no return required.
*/
return null;
}, backEndThreads.POOL)
.handle((result, error) -> {
if (error != null) {
log.warn("fetchMarkdown: pp={}, fetch error={}",
pp, error);
releaseCountDownLatch(markdownLatchMap, mdmKey);
}
return null;
});
return freshLatch;
}
}
/*
* Call when fetchXXX operation has completed either
* successfully or on error. Remove latch associated with
* operation from xxxLatchMap to permit future operations
* on /{user}/{repo}/{branch} associated with latchKey.
*/
private void releaseCountDownLatch(ConcurrentHashMap<String,
CountDownLatch> latchMap,
String latchKey) {
CountDownLatch completedLatch = latchMap.remove(latchKey);
if (completedLatch != null) {
completedLatch.countDown();
}
}
private static final String GHUB_REPO_META =
"https://api.github.com/repos/";
private static final String GIT_MASTER = "master";
private static final String SLASH = "/";
private static final int HTTP_OK = 200;
private static final int STATUS_OK = 0;
private static final String API_HEADER_AUTH = "Authorization";
private static final String API_HEADER_TOKEN = "token ";
private static final String API_RATE_LIMIT = "X-RateLimit-Limit";
private static final String API_RATE_LIMIT_REMAINING = "X-RateLimit-Remaining";
}

View File

@ -1,177 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.DelimParams;
import com.gitpitch.utils.YAMLOptions;
import org.apache.commons.io.FilenameUtils;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md image support service.
*/
@Singleton
public class ImageService {
private final Logger.ALogger log = Logger.of(this.getClass());
public String buildBackground(PitchParams pp,
YAMLOptions yOpts) {
return buildBackground(yOpts.fetchImageBg(pp),
yOpts.fetchImageBgSize(pp),
yOpts.fetchImageBgColor(pp),
yOpts.fetchImageBgPosition(pp),
yOpts.fetchImageBgRepeat(pp),
yOpts.fetchTransition(pp));
}
public String buildBackground(String md,
DelimParams dp,
PitchParams pp,
String defaultSize,
String defaultColor,
String defaultPos,
String defaultRepeat,
String defaultTransition,
MarkdownModel mdm) {
String bgUrl = dp.get(MarkdownModel.DELIM_QUERY_IMAGE);
bgUrl = mdm.linkLive(pp, bgUrl);
String bgSize = dp.get(MarkdownModel.DELIM_QUERY_SIZE, defaultSize);
String bgColor = dp.get(MarkdownModel.DELIM_QUERY_COLOR, defaultColor);
String bgPos = dp.get(MarkdownModel.DELIM_QUERY_POSITION, defaultPos);
String bgRepeat =
dp.get(MarkdownModel.DELIM_QUERY_REPEAT, defaultRepeat);
String bgTransition =
dp.get(MarkdownModel.DELIM_QUERY_TRANSITION, defaultTransition);
return buildBackground(bgUrl, bgSize, bgColor, bgPos, bgRepeat, bgTransition);
}
private String buildBackground(String bgUrl,
String bgSize,
String bgColor,
String bgPosition,
String bgRepeat,
String bgTransition) {
return new StringBuffer(MarkdownModel.MD_SPACER)
.append(MarkdownModel.MD_IMAGE_OPEN)
.append(bgUrl)
.append(MarkdownModel.MD_IMAGE_SIZE)
.append(bgSize)
.append(MarkdownModel.MD_IMAGE_COLOR)
.append(bgColor)
.append(MarkdownModel.MD_IMAGE_POSITION)
.append(bgPosition)
.append(MarkdownModel.MD_IMAGE_REPEAT)
.append(bgRepeat)
.append(MarkdownModel.MD_IMAGE_TRANSITION)
.append(bgTransition)
.append(MarkdownModel.MD_CLOSER)
.append(MarkdownModel.MD_SPACER)
.toString();
}
public String buildBackgroundOffline(String md) {
try {
String frag = md.substring(MarkdownModel.MD_IMAGE_OPEN.length());
String fragUrl = frag.substring(0, frag.indexOf("\""));
String imageName = FilenameUtils.getName(fragUrl);
String imageUrl = IMG_OFFLINE_DIR + imageName;
return md.replace(fragUrl, imageUrl);
} catch (Exception bex) {
}
return md;
}
public String buildInlineOffline(String imageName) {
return new StringBuffer(IMG_INLINE_OPEN).append(imageName)
.append(IMG_INLINE_CLOSE)
.toString();
}
public String buildTagOffline(String md) {
try {
String imageTagUrl = tagLink(md);
String imageTagName = FilenameUtils.getName(imageTagUrl);
String offlineTagUrl = IMG_OFFLINE_DIR + imageTagName;
return md.replace(imageTagUrl, offlineTagUrl);
} catch(Exception tex) {}
return md;
}
public boolean inline(String md) {
return md.startsWith(MarkdownModel.MD_LINK_OPEN);
}
public boolean background(String md) {
return md.contains(MarkdownModel.DATA_IMAGE_ATTR);
}
/*
* Return true is HTML image tag found.
*/
public boolean tagFound(String md) {
return md.startsWith(IMG_TAG_OPEN);
}
public String tagLink(String md) {
int linkTagStart = md.indexOf(IMG_TAG_SRC_OPEN);
int linkStart = linkTagStart + IMG_TAG_SRC_OPEN.length();
int linkEnd =
md.indexOf(IMG_TAG_SRC_CLOSE, linkStart);
String tagLink = IMG_TAG_LINK_UNKNOWN;
if(linkTagStart != -1 && linkEnd != -1) {
tagLink = md.substring(linkStart, linkEnd);
}
return tagLink;
}
private static final String IMG_OFFLINE_DIR = "./assets/md/assets/";
private static final String IMG_INLINE_OPEN = "![Image](" + IMG_OFFLINE_DIR;
private static final String IMG_INLINE_CLOSE = ")";
private static final String IMG_TAG_OPEN = "<img ";
private static final String IMG_TAG_SRC_OPEN = "src=\"";
private static final String IMG_TAG_SRC_CLOSE = "\"";
private static final String IMG_TAG_LINK_UNKNOWN = "#";
private static final String IMG_CUSTOM_SIZE_OPTION = "&size=";
}

View File

@ -1,657 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.factory.MarkdownModelFactory;
import com.gitpitch.git.*;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.executors.BackEndThreads;
import com.gitpitch.policies.Runtime;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.YAMLOptions;
import com.gitpitch.utils.MarkdownRenderer;
import org.apache.commons.io.FilenameUtils;
import play.Logger;
import javax.inject.*;
import java.io.File;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.FileSystems;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* PITCHME.zip archive offline service.
*/
@Singleton
public class OfflineService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final GRSManager grsManager;
private final DiskService diskService;
private final ShellService shellService;
private final MarkdownModelFactory markdownModelFactory;
private final BackEndThreads backEndThreads;
private final Runtime runtime;
@Inject
public OfflineService(GRSManager grsManager,
DiskService diskService,
ShellService shellService,
MarkdownModelFactory markdownModelFactory,
BackEndThreads backEndThreads,
Runtime runtime) {
this.grsManager = grsManager;
this.diskService = diskService;
this.shellService = shellService;
this.markdownModelFactory = markdownModelFactory;
this.backEndThreads = backEndThreads;
this.runtime = runtime;
}
/*
* Generate and fetch PITCHME.zip.
*/
public CountDownLatch fetchZip(PitchParams pp,
Optional<SlideshowModel> ssmo) {
log.debug("fetchZip: pp={}, ssmo.isPresent={}",
pp, ssmo.isPresent());
final String zipKey = MarkdownModel.genKey(pp);
CountDownLatch freshLatch = new CountDownLatch(1);
CountDownLatch activeLatch =
zipLatchMap.putIfAbsent(zipKey, freshLatch);
if (activeLatch != null) {
/*
* A non-null activeLatch implies a fetchZip()
* operation is already in progress for the current
* /{user}/{repo}?b={branch}.
*/
log.debug("fetchZip: pp={}, already in progress, " +
"returning existing activeLatch={}", pp, activeLatch);
return activeLatch;
} else {
CompletableFuture<Void> syncFuture =
CompletableFuture.supplyAsync(() -> {
Path branchPath = diskService.ensure(pp);
int zipStatus = generateZip(pp, ssmo);
if (zipStatus != STATUS_OK) {
log.warn("fetchZip: pp={}, fetch status={}", pp, zipStatus);
}
/*
* Current operation completed, so remove latch associated
* with operation from zipLatchMap to permit future
* operations on this /{user}/{repo}?b={branch}.
*/
releaseCountDownLatch(zipLatchMap, zipKey);
/*
* Operation completed, valid result cached, no return required.
*/
return null;
}, backEndThreads.POOL)
.handle((result, error) -> {
if (error != null) {
log.warn("fetchZip: pp={}, fetch error={}", pp, error);
releaseCountDownLatch(zipLatchMap, zipKey);
}
return null;
});
return freshLatch;
}
}
/*
* Call when fetchXXX operation has completed either
* successfully or on error. Remove latch associated with
* operation from xxxLatchMap to permit future operations
* on /{user}/{repo}?b={branch} associated with latchKey.
*/
private void releaseCountDownLatch(ConcurrentHashMap<String, CountDownLatch> latchMap,
String latchKey) {
CountDownLatch completedLatch = latchMap.remove(latchKey);
if (completedLatch != null) {
completedLatch.countDown();
}
}
/*
* Generate offline slideshow as self-contained zip archive.
*/
private int generateZip(PitchParams pp,
Optional<SlideshowModel> ssmo) {
log.debug("generateZip: pp={}, ssmo.isPresent={}",
pp, ssmo.isPresent());
int status = STATUS_UNDEF;
Path zipRoot = null;
try {
zipRoot = prepareZipRoot(pp);
status = fetchOnlineMarkdown(pp, zipRoot);
if (status == STATUS_OK)
status = processMarkdown(pp, zipRoot, ssmo);
if (status == STATUS_OK)
status = fetchSlideshowHTML(pp, zipRoot);
if (status == STATUS_OK)
status = fetchMenuHTML(pp, zipRoot);
if (status == STATUS_OK)
fetchFixedDependencies(pp, zipRoot);
if (status == STATUS_OK)
fetchYAMLDependencies(pp, zipRoot);
if (status == STATUS_OK)
pruneYAMLDependencies(pp, zipRoot);
if (status == STATUS_OK)
status = buildZip(pp, zipRoot);
} catch (Exception zex) {
log.warn("generateZip: pp={}, ex={}", zex);
} finally {
/*
* Clean up artifacts if failed to generate zip.
*/
if (status != STATUS_OK && zipRoot != null) {
diskService.delete(zipRoot.resolve(PITCHME_ZIP));
diskService.deepDelete(zipRoot.resolve(ZIP_ROOT_DIR).toFile());
}
}
return status;
}
/*
* Prepare zip archive root directory on disk.
*/
private Path prepareZipRoot(PitchParams pp) {
Path zipRoot = diskService.ensure(pp);
if(pp.pitchme != null) {
zipRoot = zipRoot.resolve(pp.pitchme);
}
zipRoot = zipRoot.resolve(ZIP_ROOT_DIR);
return diskService.ensure(zipRoot);
}
/*
* Fetch online PITCHME.md into ZIP_MD_DIR.
*/
private int fetchOnlineMarkdown(PitchParams pp, Path zipRoot) {
String murl =
com.gitpitch.controllers.routes.PitchController.markdown(pp.grs,
pp.user,
pp.repo,
pp.branch,
pp.pitchme)
.absoluteURL(isEncrypted(), hostname());
Path zipMdPath =
diskService.ensure(zipRoot.resolve(ZIP_MD_DIR));
return diskService.download(pp,
zipMdPath, murl, PITCHME_ONLINE_MD,
grsManager.get(pp).getHeaders());
}
/*
* Fetch Slideshow.html.
*/
private int fetchSlideshowHTML(PitchParams pp, Path zipRoot) {
String lurl =
com.gitpitch.controllers.routes.PitchController.slideshow(pp.user,
pp.repo,
pp.branch,
pp.grs,
pp.theme,
pp.pitchme,
pp.notes,
ENABLED, null, null)
.absoluteURL(isEncrypted(), hostname());
return diskService.download(pp, zipRoot,
lurl, INDEX_HTML, grsManager.get(pp).getHeaders());
}
/*
* Fetch Menu.html.
*/
private int fetchMenuHTML(PitchParams pp, Path zipRoot) {
String surl =
com.gitpitch.controllers.routes.PitchController.home(pp.grs,
pp.user,
pp.repo,
pp.branch,
pp.theme,
pp.pitchme,
ENABLED)
.absoluteURL(isEncrypted(), hostname());
return diskService.download(pp, zipRoot,
surl, MENU_HTML, grsManager.get(pp).getHeaders());
}
/*
* Fetch fixed JS and CSS dependencies for GitPitch slideshow.
*/
private void fetchFixedDependencies(PitchParams pp, Path zipRoot)
throws java.io.IOException {
Path destPath =
diskService.ensure(zipRoot.resolve(ZIP_ASSETS_DIR));
if(runtime.isProd()) {
Path jarPath = prodModeDependenciesJar();
if(jarPath.toFile().exists()) {
diskService.copyDirectoryFromJar(jarPath,
FIXED_ASSETS, destPath);
} else {
log.warn("fetchFixedDependencies: [ prod ] jar " +
"not found={}", jarPath);
}
} else {
Path fixedAssetsPath = devModeFixedDependencies();
if (fixedAssetsPath.toFile().exists()) {
diskService.copyDirectory(fixedAssetsPath, destPath);
} else {
log.debug("fetchFixedDependencies: [ dev ] fixed assets " +
"not found={}", fixedAssetsPath);
}
}
}
/*
* Convert online PITCHME.md to offline PITCHME.md.
*/
private int processMarkdown(PitchParams pp,
Path zipRoot,
Optional<SlideshowModel> ssmo) {
int status = STATUS_UNDEF;
String consumed = null;
Path mdOnlinePath = zipRoot.resolve(PITCHME_ONLINE_PATH);
File mdOnlineFile = mdOnlinePath.toFile();
if (mdOnlineFile.exists()) {
GRSService grsService =
grsManager.getService(grsManager.get(pp));
MarkdownRenderer mrndr =
MarkdownRenderer.build(pp, ssmo, grsService, diskService);
MarkdownModel markdownModel =
(MarkdownModel) markdownModelFactory.create(mrndr);
try (Stream<String> stream = Files.lines(mdOnlinePath)) {
consumed = stream.map(md -> {
return markdownModel.offline(md);
}).collect(Collectors.joining("\n"));
Path mdOfflinePath =
zipRoot.resolve(PITCHME_OFFLINE_PATH);
Files.write(mdOfflinePath, consumed.getBytes());
fetchOnlineAssets(pp, zipRoot);
status = STATUS_OK;
} catch (Exception mex) {
log.warn("processMarkdown: ex={}", mex);
}
} else {
log.warn("processMarkdown: mdOnline not found={}", mdOnlineFile);
}
log.debug("processMarkdown: returning status={}", status);
return status;
}
/*
* Fetch online PITCHME.md image assets into ZIP_MD_ASSETS_DIR.
*/
private void fetchOnlineAssets(PitchParams pp, Path zipRoot) {
List<String> assetUrls = null;
Path mdOnlinePath = zipRoot.resolve(PITCHME_ONLINE_PATH);
File mdOnlineFile = mdOnlinePath.toFile();
if (mdOnlineFile.exists()) {
MarkdownModel markdownModel =
(MarkdownModel) markdownModelFactory.create(null);
try (Stream<String> stream = Files.lines(mdOnlinePath)) {
assetUrls = stream.map(md -> {
return markdownModel.offlineAssets(md);
}).collect(Collectors.toList());
log.debug("fetchOnlineAssets: assetUrls={}", assetUrls);
Path zipMdAssetsPath = zipRoot.resolve(ZIP_MD_ASSETS_DIR);
zipMdAssetsPath = diskService.ensure(zipMdAssetsPath);
List<String> fetched = new ArrayList<String>();
for (String assetUrl : assetUrls) {
if (assetUrl != null &&
!fetched.contains(assetUrl)) {
diskService.download(pp, zipMdAssetsPath, assetUrl,
FilenameUtils.getName(assetUrl),
grsManager.get(pp).getHeaders());
fetched.add(assetUrl);
}
}
} catch (Exception mex) {
log.warn("fetchOnlineAssets: ex={}", mex);
}
} else {
log.warn("fetchOnlineAssets: mdOnline not found={}", mdOnlineFile);
}
}
/*
* Fetch PITCHME.yaml dependencies into zip archive.
*/
private void fetchYAMLDependencies(PitchParams pp, Path zipRoot) {
GRSService grsService =
grsManager.getService(grsManager.get(pp));
YAMLOptions yOpts = YAMLOptions.build(pp, grsService, diskService);
log.debug("fetchYAMLDependencies: yOpts={}", yOpts);
try {
if (yOpts != null && yOpts.hasLogo()) {
String logoUrl = yOpts.fetchLogo(pp);
String logoName = FilenameUtils.getName(logoUrl);
Path zipAssetsPath =
diskService.ensure(zipRoot.resolve(ZIP_ASSETS_DIR));
diskService.download(pp, zipAssetsPath,
logoUrl, logoName, grsManager.get(pp).getHeaders());
log.debug("fetchYAMLDependencies: downloaded logo={}", logoUrl);
}
} catch (Exception lex) {
log.warn("fetchYAMLDependencies: logo ex={}", lex);
}
}
/*
* Prune unused PITCHME.yaml dependencies from zip archive.
*/
private void pruneYAMLDependencies(PitchParams pp, Path zipRoot) {
GRSService grsService =
grsManager.getService(grsManager.get(pp));
YAMLOptions yOpts = YAMLOptions.build(pp, grsService, diskService);
log.debug("pruneYAMLDependencies: yOpts={}", yOpts);
Path destPath = zipRoot.resolve(ZIP_ASSETS_DIR);
String liveRevealVersion =
runtime.config("gitpitch.dependency.revealjs");
if(yOpts != null && yOpts.fetchRevealVersion(pp) != null) {
liveRevealVersion = yOpts.fetchRevealVersion(pp);
}
try {
/*
* Strip Reveal.js distributions (X.y.z) unused by GitPitch.
*/
for(String distroVersion : REVEALJS_DISTRO_VERSIONS) {
if(!distroVersion.equals(liveRevealVersion)) {
Path distroPath =
buildLibraryPath(destPath, "reveal.js", distroVersion);
log.debug("pruneYAMLDependencies: removing distro={}",
distroPath);
diskService.deepDelete(distroPath.toFile());
}
}
} catch (Exception mex) {
log.warn("pruneYAMLDependencies: unused plugin assets ex={}", mex);
}
try {
/*
* If Math Slides not enabled within PITCHME.yaml, strip
* Reveal.js math plugin file dependencies from zip.
*/
if (yOpts == null || !yOpts.mathEnabled(pp)) {
Path mathPluginPath =
buildLibraryPath(destPath,
"reveal.js",
liveRevealVersion,
"plugin/math");
log.debug("pruneYAMLDependencies: removing mathPlugin={}",
mathPluginPath);
diskService.deepDelete(mathPluginPath.toFile());
}
} catch (Exception mex) {
log.warn("pruneYAMLDependencies: math config assets ex={}", mex);
}
try {
/*
* If Chart slides not enabled within PITCHME.yaml, strip
* Reveal.js charts plugin file dependencies from zip.
*/
if (yOpts == null || !yOpts.fetchCharts(pp)) {
Path chartPluginPath =
buildLibraryPath(destPath,
"reveal.js",
liveRevealVersion,
"plugin/chart");
log.debug("pruneYAMLDependencies: removing chartPlugin={}",
chartPluginPath);
diskService.deepDelete(chartPluginPath.toFile());
}
} catch (Exception mex) {
log.warn("pruneYAMLDependencies: math config assets ex={}", mex);
}
try {
/*
* Strip Reveal.js standard dist plugins unused by GitPitch.
*/
for(String pluginName : OFFLINE_UNUSED_PLUGINS) {
Path unusedPath =
buildLibraryPath(destPath,
"reveal.js",
liveRevealVersion,
"plugin/"+ pluginName);
log.debug("pruneYAMLDependencies: removing unused={}",
unusedPath);
diskService.deepDelete(unusedPath.toFile());
}
} catch (Exception mex) {
log.warn("pruneYAMLDependencies: unused plugin assets ex={}", mex);
}
}
/*
* Build PITCHME.zip.
*/
private int buildZip(PitchParams pp, Path zipRoot) {
/*
* Remove PITCHME_ONLINE_MD from zip directory.
*/
Path onlinePath = zipRoot.resolve(PITCHME_ONLINE_PATH);
diskService.delete(onlinePath);
/*
* CMD: zip -r PITCHME.zip PITCHME
*/
String[] cmd = {ZIP_CMD,
ZIP_QUIET,
ZIP_ALL,
PITCHME_ZIP,
ZIP_ROOT_DIR};
Path zipWd = diskService.ensure(pp, pp.pitchme);
return shellService.exec(ZIP_CMD, pp, zipWd, cmd);
}
public boolean isEncrypted() {
return runtime.configBool("gitpitch.https");
}
public String hostname() {
return runtime.config("gitpitch.hostname");
}
public Path devModeFixedDependencies() {
String fixedAssets =
runtime.config("gitpitch.offline.dev.fixed.assets.home");
return Paths.get(fixedAssets);
}
public Path prodModeDependenciesJar() {
String jarAssets =
runtime.config("gitpitch.offline.prod.fixed.assets.home");
return Paths.get(jarAssets);
}
private Path buildLibraryPath(Path basePath,
String libName,
String libVersion) {
return buildLibraryPath(basePath, libName, libVersion, null);
}
private Path buildLibraryPath(Path basePath,
String libName,
String libVersion,
String dirName) {
if(dirName != null)
return Paths.get(basePath.toString(), libName, libVersion, dirName);
else
return Paths.get(basePath.toString(), libName, libVersion);
}
private static final String ZIP_ROOT_DIR = "PITCHME";
private static final String ZIP_MD_DIR = "assets/md";
private static final String ZIP_MD_ASSETS_DIR = "assets/md/assets";
private static final String ZIP_ASSETS_DIR = "assets";
private static final String PITCHME_ONLINE_MD = "PITCHME.mdo";
private static final String PITCHME_OFFLINE_MD = "PITCHME.md";
private static final String PITCHME_ONLINE_PATH =
ZIP_MD_DIR + "/" + PITCHME_ONLINE_MD;
private static final String PITCHME_OFFLINE_PATH =
ZIP_MD_DIR + "/" + PITCHME_OFFLINE_MD;
private static final String PITCHME_ZIP = "PITCHME.zip";
private static final String PITCHME_CSS = "PITCHME.css";
private static final String INDEX_HTML = "index.html";
private static final String SLIDESHOW_HTML = "pitchme.html";
private static final String MENU_HTML = "menu.html";
private static final String FIXED_ASSETS = "/public/libs";
private static final String FIXED_ASSETS_MATH = "/public/libs-math";
private static final String ZIP_CMD = "zip";
private static final String ZIP_QUIET = "-q";
private static final String ZIP_ALL = "-r";
private static final String ENABLED = "true";
private static final int STATUS_OK = 0;
private static final int STATUS_UNDEF = 999;
private static final List<String> REVEALJS_DISTRO_VERSIONS =
java.util.Arrays.asList("3.3.1", "3.4.1", "3.5.0");
private static final List<String> OFFLINE_UNUSED_PLUGINS =
java.util.Arrays.asList("multiplex",
"notes-server",
"search",
"zoom-js",
"print-pdf");
private final ConcurrentHashMap<String, CountDownLatch> zipLatchMap =
new ConcurrentHashMap();
}

View File

@ -1,293 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.GitRepoModel;
import com.gitpitch.models.Markdown;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.policies.CacheTimeout;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.cache.*;
import play.libs.ws.*;
import javax.inject.*;
import java.io.File;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
/*
* Support service for controllers.PitchController actions.
*/
@Singleton
public class PitchService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final static String PITCHME_PDF = "PITCHME.pdf";
private final static String PITCHME_ZIP = "PITCHME.zip";
private final static String PITCHME_ZIP_DIR = "PITCHME";
private final CacheApi pitchCache;
private final DiskService diskService;
private final GitService gitService;
private final PrintService printService;
private final OfflineService offlineService;
private final CacheTimeout cacheTimeout;
@Inject
public PitchService(CacheApi pitchCache,
DiskService diskService,
GitService gitService,
PrintService printService,
OfflineService offlineService,
CacheTimeout cacheTimeout) {
this.pitchCache = pitchCache;
this.diskService = diskService;
this.gitService = gitService;
this.printService = printService;
this.offlineService = offlineService;
this.cacheTimeout = cacheTimeout;
}
/*
* Return cached GitRepoModel, else Optional.empty.
*/
public Optional<GitRepoModel> cachedRepo(PitchParams pp) {
String grmKey = GitRepoModel.genKey(pp);
log.debug("cachedRepo: grmKey={}", grmKey);
return Optional.ofNullable(pitchCache.get(grmKey));
}
/*
* Return GitRepoModel.
*/
public GitRepoModel fetchRepo(PitchParams pp) {
log.debug("fetchRepo: pp={}", pp);
CountDownLatch repoLatch = gitService.fetchRepo(pp);
try {
/*
* Block until GitService.repoFetch() completes.
* On success the GitService.repoFetch() will
* populate the pitchCache with a valid RepoModel
* for /{user}/{repo}/{branch}. On failure, null.
*/
repoLatch.await();
} catch (Exception ex) {
log.warn("fetchRepo: pp={}, repoLatch.await ex={}", pp, ex);
}
Optional<GitRepoModel> grmo = cachedRepo(pp);
GitRepoModel grm = grmo.orElse(null);
log.debug("fetchRepo: pp={}, returning grm={}", pp, grm);
return grm;
}
/*
* Return cached SlideshowModel, else Optional.empty.
*/
public Optional<SlideshowModel> cachedYAML(PitchParams pp) {
String ssmKey = SlideshowModel.genKey(pp);
return Optional.ofNullable(pitchCache.get(ssmKey));
}
/*
* Return SlideshowModel.
*/
public SlideshowModel fetchYAML(PitchParams pp) {
log.debug("fetchYAML: pp={}", pp);
CountDownLatch slideshowLatch = gitService.fetchYAML(pp);
try {
/*
* Block until GitService.fetchYAML() completes.
* On success the GitService.fetchYAML() will
* populate the pitchCache with a valid SlideshowModel
* for /{user}/{repo}/{branch}. On failure, null.
*/
slideshowLatch.await();
} catch (Exception ex) {
log.warn("fetchYAML: pp={}, slideshowLatch.await ex={}", pp, ex);
}
Optional<SlideshowModel> ssmo = cachedYAML(pp);
SlideshowModel ssm = ssmo.orElse(null);
log.debug("fetchYAML: pp={}, returning ssm={}", pp, ssm);
return ssm;
}
/*
* Return cached MarkdownModel, else Optional.empty.
*/
public Optional<Markdown> cachedMarkdown(PitchParams pp) {
String mdmKey = MarkdownModel.genKey(pp);
return Optional.ofNullable(pitchCache.get(mdmKey));
}
/*
* Return RepoModel.
*/
public Markdown fetchMarkdown(PitchParams pp) {
log.debug("fetchMarkdown: pp={}", pp);
CountDownLatch markdownLatch = gitService.fetchMarkdown(pp);
try {
/*
* Block until GitService.fetchMarkdown() completes.
* On success the GitService.fetchMarkdown() will
* populate the pitchCache with a valid MarkdownModel
* for /{user}/{repo}/{branch}. On failure, null.
*/
markdownLatch.await();
} catch (Exception ex) {
log.warn("fetchMarkdown: pp={}, markdownLatch.await ex={}", pp, ex);
}
Optional<Markdown> mdmo = cachedMarkdown(pp);
Markdown mdm = mdmo.orElse(null);
log.debug("fetchMarkdown: pp={}, returning mdm={}", pp, mdm);
return mdm;
}
/*
* Return cached PITCHME.pdf, else Optional.empty.
*/
public Optional<File> cachedPDF(PitchParams pp) {
File pdfFile = diskService.asFile(pp, pp.PDF());
long pdfAge = System.currentTimeMillis() - pdfFile.lastModified();
log.debug("cachedPDF: pdfAge={}, max={}, file={}",
pdfAge, cacheTimeout.pdf(pp), pdfFile);
if (pdfAge > cacheTimeout.pdf(pp)) {
diskService.delete(pp, pp.PDF());
}
return pdfFile.exists() ? Optional.of(pdfFile) : Optional.empty();
}
/*
* Return PITCHME.pdf.
*/
public File fetchPDF(PitchParams pp) {
log.debug("fetchPDF: pp={}", pp);
CountDownLatch pdfLatch = printService.fetchPDF(pp);
try {
/*
* Block until PrintService.fetchPDF() completes.
* On success the PrintService.fetchPDF() will
* have built PITCHME.pdf on the file system
* for /{user}/{repo}/{branch}. On failure, null.
*/
pdfLatch.await();
} catch (Exception ex) {
log.warn("fetchPDF: pp={}, pdfLatch.await ex={}", pp, ex);
}
Optional<File> pdfo = cachedPDF(pp);
File pdf = pdfo.orElse(null);
log.debug("fetchPDF: pp={}, returning pdf={}", pp, pdf);
return pdf;
}
/*
* Return cached PITCHME.zip, else Optional.empty.
*/
public Optional<File> cachedZip(PitchParams pp) {
Path zipPath = diskService.ensure(pp, pp.pitchme);
File zipFile = zipPath.resolve(PITCHME_ZIP).toFile();
long zipAge = System.currentTimeMillis() - zipFile.lastModified();
log.debug("cachedZip: zipAge={}, max={}, file={}",
zipAge, cacheTimeout.zip(pp), zipFile);
if (zipAge > cacheTimeout.zip(pp)) {
diskService.delete(zipPath.resolve(PITCHME_ZIP));
diskService.deepDelete(zipPath.resolve(PITCHME_ZIP_DIR).toFile());
log.debug("cachedZip: deleted expired zip artifacts.");
}
return zipFile.exists() ? Optional.of(zipFile) : Optional.empty();
}
/*
* Return PITCHME.zip.
*/
public File fetchZip(PitchParams pp) {
log.debug("fetchZip: pp={}", pp);
CountDownLatch zipLatch =
offlineService.fetchZip(pp, cachedYAML(pp));
try {
/*
* Block until OfflineService.fetchZip() completes.
* On success the OfflineService.fetchZip() will
* have built PITCHME.zip on the file system
* for /{user}/{repo}/{branch}. On failure, null.
*/
zipLatch.await();
} catch (Exception ex) {
log.warn("fetchZip: pp={}, zipLatch.await ex={}", pp, ex);
}
Optional<File> zipo = cachedZip(pp);
File zip = zipo.orElse(null);
log.debug("fetchZip: pp={}, returning zip={}", pp, zip);
return zip;
}
/*
* Return file at path, else Optional.empty.
*/
public Optional<File> raw(PitchParams pp, String path) {
File rawFile = diskService.asFile(pp, path);
return rawFile.exists() ? Optional.of(rawFile) : Optional.empty();
}
}

View File

@ -1,209 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.executors.BackEndThreads;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.YAMLOptions;
import com.gitpitch.policies.Runtime;
import play.Logger;
import javax.inject.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/*
* PITCHME.pdf document print service.
*/
@Singleton
public class PrintService {
private final Logger.ALogger log = Logger.of(this.getClass());
private DiskService diskService;
private ShellService shellService;
private BackEndThreads backEndThreads;
private Runtime runtime;
@Inject
public PrintService(DiskService diskService,
ShellService shellService,
BackEndThreads backEndThreads,
Runtime runtime) {
this.diskService = diskService;
this.shellService = shellService;
this.backEndThreads = backEndThreads;
this.runtime = runtime;
}
/*
* Generate and fetch PITCHME.pdf.
*/
public CountDownLatch fetchPDF(PitchParams pp) {
log.debug("fetchPDF: pp={}", pp);
final String pdfKey = MarkdownModel.genKey(pp);
CountDownLatch freshLatch = new CountDownLatch(1);
CountDownLatch activeLatch =
pdfLatchMap.putIfAbsent(pdfKey, freshLatch);
if (activeLatch != null) {
/*
* A non-null activeLatch implies a fetchPDF()
* operation is already in progress for the current
* /{user}/{repo}?b={branch}.
*/
log.debug("fetchPDF: pp={}, already in progress, " +
"returning existing activeLatch={}", pp, activeLatch);
return activeLatch;
} else {
CompletableFuture<Void> syncFuture =
CompletableFuture.supplyAsync(() -> {
Path branchPath = diskService.ensure(pp, pp.pitchme);
int pdfStatus = generatePDF(pp);
if (pdfStatus != STATUS_OK) {
log.warn("fetchPDF: pp={}, fetch status={}", pp, pdfStatus);
}
/*
* Current operation completed, so remove latch associated
* with operation from pdfLatchMap to permit future
* operations on this /{user}/{repo}?b={branch}.
*/
releaseCountDownLatch(pdfLatchMap, pdfKey);
/*
* Operation completed, valid result cached, no return required.
*/
return null;
}, backEndThreads.POOL)
.handle((result, error) -> {
if (error != null) {
log.warn("fetchPDF: pp={}, fetch error={}", pp, error);
releaseCountDownLatch(pdfLatchMap, pdfKey);
}
return null;
});
return freshLatch;
}
}
/*
* Call when fetchXXX operation has completed either
* successfully or on error. Remove latch associated with
* operation from xxxLatchMap to permit future operations
* on /{user}/{repo}?b={branch} associated with latchKey.
*/
private void releaseCountDownLatch(ConcurrentHashMap<String, CountDownLatch> latchMap,
String latchKey) {
CountDownLatch completedLatch = latchMap.remove(latchKey);
if (completedLatch != null) {
completedLatch.countDown();
}
}
/*
* Generate PDF using DeckTape command line service.
*/
private int generatePDF(PitchParams pp) {
log.debug("generatePDF: pp={}", pp);
Path branchPath = diskService.ensure(pp);
diskService.delete(pp, pp.PDF());
String filePath = diskService.asFile(pp, pp.PDF()).toString();
boolean printFrags = false;
try {
printFrags =
YAMLOptions.build(pp, null, diskService).printFrags(pp);
} catch(Exception ex) {}
String slideshowUrl =
com.gitpitch.controllers.routes.PitchController.slideshow(pp.user,
pp.repo,
pp.branch,
pp.grs,
pp.theme,
pp.pitchme,
pp.notes,
null,
Boolean.toString(printFrags),
null)
.absoluteURL(isEncrypted(),
hostname());
String deckTape = diskService.decktape();
String[] cmd =
{ deckTape, REVEAL, slideshowUrl, filePath, decktapeArgs()};
int generated = shellService.exec(GIT_PDF, pp, branchPath, cmd);
if (generated != STATUS_OK) {
log.warn("generatePDF: pp={}, generate status={}", pp, generated);
}
return generated;
}
public boolean isEncrypted() {
return runtime.configBool("gitpitch.https");
}
public String hostname() {
return runtime.config("gitpitch.hostname");
}
private String decktapeArgs() {
String args = runtime.config("gitpitch.decktape.args");
return (args != null) ? args : "";
}
private static final String REVEAL = "reveal";
private static final String PITCHME_PDF = "PITCHME.pdf";
private static final String GIT_PDF = "pdf";
private static final int STATUS_OK = 0;
private final ConcurrentHashMap<String, CountDownLatch> pdfLatchMap =
new ConcurrentHashMap();
}

View File

@ -1,73 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import javax.inject.*;
import java.io.IOException;
import java.nio.file.Path;
/*
* Shell command execution service.
*/
@Singleton
public class ShellService {
private final Logger.ALogger log = Logger.of(this.getClass());
public int exec(String op, PitchParams pp, Path wd, String... cmd) {
int resp = STATUS_UDEF;
try {
long startProc = System.currentTimeMillis();
Process cmdProc = new ProcessBuilder(cmd).inheritIO()
.directory(wd.toFile())
.start();
resp = cmdProc.waitFor();
log.debug("exec: op={}, pp={}, time taken={}", op, pp,
(System.currentTimeMillis() - startProc));
} catch (IOException ioex) {
log.warn("exec: op={}, pp={}, ioex={}", op, pp, ioex);
resp = STATUS_IO_EX;
} catch (InterruptedException iex) {
log.warn("exec: op={}, pp={}, iex={}", op, pp, iex);
resp = STATUS_INT_EX;
}
return resp;
}
private static final int STATUS_OK = 0;
private static final int STATUS_IO_EX = -777;
private static final int STATUS_INT_EX = -888;
private static final int STATUS_UDEF = -999;
}

View File

@ -1,271 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.YAMLOptions;
import org.apache.commons.io.FilenameUtils;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md feature-shortcuts support service.
*/
@Singleton
public class ShortcutsService {
private final Logger.ALogger log = Logger.of(this.getClass());
public String process(String md, PitchParams pp, YAMLOptions yOpts) {
String processed = md;
try {
int faCycles = 5; // Prevent infinite loop.
while(fontAwesomeFound(processed) && faCycles > 0) {
String expanded = expandFontAwesome(processed);
faCycles = processed.equals(expanded) ? 0 : (faCycles-1);
processed = expanded;
}
} catch(Exception ex) {}
return processed;
}
public boolean listFragmentFound(String md) {
boolean found = false;
if(md != null) {
String trimmed = md.trim();
if(trimmed.startsWith(MarkdownModel.MD_LIST_FRAG_OPEN) &&
trimmed.endsWith(MarkdownModel.MD_LIST_FRAG_CLOSE)) {
found = true;
}
}
return found;
}
public boolean codeFragmentFound(String md) {
boolean found = false;
if(md != null) {
if(md.startsWith(MarkdownModel.MD_CODE_FRAG_OPEN)) {
found = true;
}
}
return found;
}
public boolean titleHintFound(String md) {
boolean found = false;
if(md != null) {
if(md.startsWith(MarkdownModel.MD_TITLE_HINT_OPEN)) {
found = true;
}
}
return found;
}
public boolean fontAwesomeFound(String md) {
boolean found = false;
if(md != null) {
if(md.contains(MarkdownModel.MD_FA_OPEN)) {
found = true;
}
}
return found;
}
/*
* Expand shortcut syntax for list fragment with fully expanded
* HTML comment syntax.
*/
public String expandListFragment(String md) {
int fragCloseIdx = md.lastIndexOf(MarkdownModel.MD_LIST_FRAG_CLOSE);
return md.substring(0, fragCloseIdx) + FRAGMENT;
}
/*
* Expand shortcut syntax for code fragment with fully expanded
* HTML span syntax with data-code-focus class.
*/
public String expandCodeFragment(String md) {
try {
String codeFragRange = null;
String codeFragNote = null;
int codeFragStart =
md.indexOf(MarkdownModel.MD_CODE_FRAG_OPEN);
int codeFragEnd =
md.indexOf(MarkdownModel.MD_CODE_FRAG_CLOSE);
if(codeFragEnd > codeFragStart) {
codeFragRange =
md.substring(codeFragStart+2, codeFragEnd);
}
int codeFragNoteStart =
md.indexOf(MarkdownModel.MD_CODE_FRAG_NOTE_OPEN);
int codeFragNoteEnd =
md.lastIndexOf(MarkdownModel.MD_CODE_FRAG_NOTE_CLOSE);
if(codeFragNoteEnd > codeFragNoteStart) {
codeFragNote =
md.substring(codeFragNoteStart+1, codeFragNoteEnd);
}
if(codeFragRange != null) {
md = buildCodeFragment(codeFragRange, codeFragNote);
}
} catch(Exception cfex) {
} finally {
return md;
}
}
/*
* Expand title-hint shortcut syntax into corresponding
* HTML hidden span for detection by menu.js.
*/
public String expandTitleHint(String md) {
try {
int hintStart =
md.indexOf(MarkdownModel.MD_TITLE_HINT_OPEN) +
MarkdownModel.MD_TITLE_HINT_OPEN.length();
int hintEnd =
md.lastIndexOf(MarkdownModel.MD_TITLE_HINT_CLOSE);
if(hintEnd > hintStart) {
String hint = md.substring(hintStart, hintEnd);
md = new StringBuffer(TITLE_HINT_SPAN_OPEN)
.append(hint)
.append(TITLE_HINT_SPAN_CLOSE)
.toString();
}
} catch(Exception cfex) {
} finally {
return md;
}
}
/*
* Expand shortcut syntax for font-awesome with fully expanded
* HTML span syntax with optional text.
*/
public String expandFontAwesome(String md) {
String mdLeft = "";
String faName = "";
String faNote = "";
String mdRight = "";
String expandedFA = "";
try {
int faOpen = md.indexOf(MarkdownModel.MD_FA_OPEN);
int faClose = md.indexOf(MarkdownModel.MD_FA_CLOSE);
if(faClose > faOpen) { /* faName exists */
mdLeft = md.substring(0, faOpen);
faName =
md.substring(faOpen + MarkdownModel.MD_FA_OPEN.length(),
faClose);
String rmd = md.substring(faClose + 1);
int faNoteOpen = rmd.indexOf(MarkdownModel.MD_FA_NOTE_OPEN);
int faNoteClose = rmd.indexOf(MarkdownModel.MD_FA_NOTE_CLOSE);
if(faNoteOpen == 0) { /* faNote immediately follows faName */
faNote =
rmd.substring(MarkdownModel.MD_FA_NOTE_OPEN.length(),
faNoteClose);
mdRight = rmd.substring(faNoteClose + 1);
} else {
mdRight = rmd;
}
expandedFA = buildFontAwesome(faName, faNote);
}
} catch(Exception ex) {
} finally {
return mdLeft + expandedFA + mdRight;
}
}
/*
* Construct a HTML fragment for a code fragment based on the
* reveal-code-focus plugin syntax:
* <span class="fragment current-only" data-code-focus="1-9">Note</span>
*/
private String buildCodeFragment(String range, String note) {
if(note == null) note = "";
return new StringBuffer(HTML_CODE_FRAG_OPEN)
.append(range)
.append(HTML_CODE_FRAG_CLOSE)
.append(note)
.append(HTML_CODE_FRAG_NOTE_CLOSE)
.toString();
}
/*
* Construct a HTML fragment for an FA icon.
*/
private String buildFontAwesome(String font, String text) {
if(text == null) text = "";
return new StringBuffer(HTML_FONT_FRAG_OPEN)
.append(font)
.append(HTML_FONT_FRAG_CLOSE)
.append(text)
.append(HTML_FONT_FRAG_TEXT_CLOSE)
.toString();
}
/*
* Note, the space before opening bracket is intentional
* so tag injection can happen directly alongside other
* text in the markdown fragment.
*/
private static final String FRAGMENT =
" <!-- .element: class=\"fragment\" -->";
private static final String HTML_CODE_FRAG_OPEN =
"<span class=\"code-presenting-annotation fragment current-only\" data-code-focus=\"";
private static final String HTML_CODE_FRAG_CLOSE = "\">";
private static final String HTML_CODE_FRAG_NOTE_CLOSE = "</span>";
private static final String TITLE_HINT_SPAN_OPEN =
"<span class=\"menu-title\" style=\"display: none\">";
private static final String TITLE_HINT_SPAN_CLOSE = "</span>";
private static final String HTML_FONT_FRAG_OPEN = "<i class=\"fa fa-";
private static final String HTML_FONT_FRAG_CLOSE = "\" aria-hidden=\"true\"> ";
private static final String HTML_FONT_FRAG_TEXT_CLOSE = "</i>";
}

View File

@ -1,122 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2017 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.services.ImageService;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.DelimParams;
import com.gitpitch.utils.YAMLOptions;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* Slide utility service.
*/
@Singleton
public class SlideService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final ImageService imageService;
@Inject
public SlideService(ImageService imageService) {
this.imageService = imageService;
}
/*
* Build basic slide structure including:
*
* 1. Clean delimiter and
* 2. Optionally slide bg-image based on YAMLOptions.hasImageBg.
* 3. Or slide color delimiter.
*/
public String build(String md,
DelimParams dp,
PitchParams pp,
YAMLOptions yOpts,
MarkdownModel mdm) {
StringBuffer structure = new StringBuffer(mdm.extractDelim(md));
try {
structure = new StringBuffer(mdm.extractDelim(md))
.append(MarkdownModel.MD_SPACER);
if (yOpts != null && yOpts.hasImageBg()) {
String yamlBg = imageService.buildBackground(pp, yOpts);
structure.append(yamlBg).append(MarkdownModel.MD_SPACER);
} else {
String cbg = buildColorMarkdown(dp);
if(cbg != null) {
structure.append(cbg).append(MarkdownModel.MD_SPACER);
}
}
} catch(Exception ex) {
log.warn("build: ex={}", ex);
}
log.debug("build: returning structure={}", structure.toString());
return structure.toString();
}
public String buildColorBackground(String md,
DelimParams dp,
PitchParams pp,
YAMLOptions yOpts,
MarkdownModel mdm) {
StringBuffer structure = new StringBuffer(mdm.extractDelim(md));
try {
structure = new StringBuffer(mdm.extractDelim(md))
.append(MarkdownModel.MD_SPACER);
String bg = buildColorMarkdown(dp);
if(bg != null) {
structure.append(bg).append(MarkdownModel.MD_SPACER);
}
} catch(Exception ex) {
log.warn("buildColorDelim: ex={}", ex);
}
log.debug("buildColorDelim: returning structure={}", structure.toString());
return structure.toString();
}
private String buildColorMarkdown(DelimParams dp) {
String bgColor = dp.get(MarkdownModel.DELIM_QUERY_COLOR, null);
String bg = MarkdownModel.MD_BG_COLOR + bgColor + MarkdownModel.MD_CLOSER;
return bgColor != null ? bg : null;
}
}

View File

@ -1,72 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2017 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.YAMLOptions;
import org.apache.commons.io.FilenameUtils;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md splash-slide support service.
*/
@Singleton
public class SplashService {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Generate presentation splash-slide markdown.
*/
public String build(String md, YAMLOptions yOpts, String delim) {
return new StringBuffer(SPLASH_OPEN).append(SPLASH_LOGO_URL)
.append(SPLASH_PAD)
.append(SPLASH_LOGO_SIZE)
.append(MarkdownModel.MD_SPACER)
.append(SPLASH_TOC)
.append(MarkdownModel.MD_SPACER)
.append(SPLASH_CLOSE)
.append(MarkdownModel.MD_SPACER)
.append(delim)
.append(MarkdownModel.MD_SPACER)
.append(md)
.toString();
}
private static final String SPLASH_OPEN =
"<section data-background-color='black' data-background-image=\"";
private static final String SPLASH_LOGO_URL =
"https://gitpitch.com/gp-splash.svg";
private static final String SPLASH_PAD = "\" ";
private static final String SPLASH_LOGO_SIZE =
"data-background-size='40%'>";
private static final String SPLASH_TOC =
"<span class='menu-title' style='display: none'>GitPitch</span>";
private static final String SPLASH_CLOSE = "</section>";
}

View File

@ -1,205 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.models.MarkdownModel;
import com.gitpitch.utils.PitchParams;
import com.gitpitch.utils.DelimParams;
import java.util.*;
import javax.inject.*;
import play.Logger;
import play.Logger.ALogger;
/*
* PITCHME.md video support service.
*/
@Singleton
public class VideoService {
private final Logger.ALogger log = Logger.of(this.getClass());
/*
* Determine if video link is valid based on MP4 extension
* or if link to popular video hosting services.
*/
public boolean isVideo(String videoLink) {
boolean isVideo = false;
if (videoLink != null) {
if (videoLink.toLowerCase().endsWith(VIDEO_MP4)) {
isVideo = true;
} else if (videoLink.contains(YOUTUBE_EMBED)) {
isVideo = true;
} else if (videoLink.contains(VIMEO_EMBED)) {
isVideo = true;
}
}
return isVideo;
}
public String buildVideo(String videoLink) {
if (videoLink.contains(YOUTUBE_EMBED)) {
/*
* Build YouTube <iframe> tag.
*
* Example link:
* https://www.youtube.com/embed/mkiDkkdGGAQ
*
* Example link with offset start time:
* https://www.youtube.com/embed/mkiDkkdGGAQ?start=121
*/
String ifrOps = (videoLink.contains("?")) ?
YTUBE_IFR_OPS_APPEND : YTUBE_IFR_OPS;
return new StringBuffer(YTUBE_DIV_OPEN).append(YTUBE_IFR_OPEN)
.append(videoLink)
.append(ifrOps)
.append(YTUBE_IFR_CLSE)
.append(YTUBE_DIV_CLSE)
.toString();
} else if (videoLink.contains(VIMEO_EMBED)) {
/*
* Build Vimeo <iframe> tag.
*
* Example link:
* https://player.vimeo.com/video/111525512
*/
return new StringBuffer(VIMEO_DIV_OPEN).append(VIMEO_IFR_OPEN)
.append(videoLink)
.append(VIMEO_IFR_FULL)
.append(VIMEO_IFR_CLSE)
.append(VIMEO_DIV_CLSE)
.toString();
} else {
/*
* Build Reveal.js HTML5 <video> tag.
*
* Example link:
* http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
*/
return new StringBuffer(RJS_VID_OPEN).append(RJS_VID_STRH)
.append(RJS_VID_AUTO)
.append(RJS_VID_SRC)
.append(videoLink)
.append(RJS_VID_CLSE)
.toString();
}
}
public String buildBackground(String md,
DelimParams dp,
PitchParams pp,
MarkdownModel mdm) {
String bgUrl = dp.get(MarkdownModel.DELIM_QUERY_VIDEO, "#");
bgUrl = mdm.linkLive(pp, bgUrl);
String loop = dp.get(MarkdownModel.DELIM_QUERY_LOOP);
String muted = dp.get(MarkdownModel.DELIM_QUERY_MUTED);
StringBuffer buf = new StringBuffer(MarkdownModel.MD_SPACER)
.append(MarkdownModel.MD_SPACER)
.append(MarkdownModel.MD_VIDEO_OPEN)
.append(bgUrl)
.append(MarkdownModel.MD_VIDEO_OPEN_END);
if(Boolean.parseBoolean(loop)) {
buf.append(MarkdownModel.MD_VIDEO_LOOP);
}
if(Boolean.parseBoolean(muted)) {
buf.append(MarkdownModel.MD_VIDEO_MUTED);
}
buf.append(MarkdownModel.MD_VIDEO_CLOSE)
.append(MarkdownModel.MD_SPACER);
return buf.toString();
}
public boolean found(String md) {
return (md != null &&
(md.contains(DATA_VIDEO_ATTR) || md.contains(DATA_VIDEO_BG_ATTR)));
}
public String offline() {
return new StringBuffer(OFFLINE_VIDEO).append(SPACER)
.append(OFFLINE_NOTICE)
.toString();
}
private static final String VIDEO_MP4 = "mp4";
/*
* Reveal.js Video Tag Frags.
*/
private static final String RJS_VID_OPEN = "<video data-video=\"true\"";
private static final String RJS_VID_STRH = "class=\"stretch\" ";
private static final String RJS_VID_AUTO = "data-autoplay ";
private static final String RJS_VID_SRC = "src=\"";
private static final String RJS_VID_CLSE = "\"></video>";
/*
* Supported Video Hosting Services.
*/
private static final String YOUTUBE_EMBED = "youtube.com/embed";
private static final String VIMEO_EMBED = "player.vimeo.com/video";
/*
* YouTube Video Embed Tag Frags.
*/
private static final String YTUBE_DIV_OPEN = "<div data-video=\"true\" class=\"stretch\">";
private static final String YTUBE_IFR_OPEN = "<iframe width=\"100%\" height=\"100%\" src=\"";
private static final String YTUBE_IFR_OPS = "?wmode=opaque&amp;rel=0&amp;vq=large\" ";
private static final String YTUBE_IFR_OPS_APPEND = "&amp;wmode=opaque&amp;rel=0&amp;vq=large\" ";
private static final String YTUBE_IFR_CLSE = "frameborder=\"0\" allowfullscreen></iframe>";
private static final String YTUBE_DIV_CLSE = "</div>";
/*
* Vimeo Video Embed Tag Frags.
*/
private static final String VIMEO_DIV_OPEN = "<div data-video=\"true\" class=\"stretch\">";
private static final String VIMEO_IFR_OPEN = "<iframe width=\"100%\" height=\"100%\" src=\"";
private static final String VIMEO_IFR_FULL = "\" webkitallowfullscreen mozallowfullscreen ";
private static final String VIMEO_IFR_CLSE = "frameborder=\"0\" allowfullscreen></iframe>";
private static final String VIMEO_DIV_CLSE = "</div>";
/*
* Video Slide Offline Support.
*/
private static final String OFFLINE_VIDEO = "#### Video Slide Disabled";
private static final String OFFLINE_NOTICE = "#### [ GitPitch Offline ]";
private static final String DATA_VIDEO_ATTR = "data-video=";
private static final String DATA_VIDEO_BG_ATTR = "data-background-video=";
private static final String SPACER = "\n";
}

View File

@ -1,132 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.services;
import com.gitpitch.utils.PitchParams;
import play.Logger;
import play.libs.ws.*;
import javax.inject.*;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/*
* HTTP(S) web service.
*/
@Singleton
public class WebService {
private final Logger.ALogger log = Logger.of(this.getClass());
private final WSClient ws;
@Inject
public WebService(WSClient ws) {
this.ws = ws;
}
public byte[] fetchBytes(PitchParams pp,
String source,
Map<String,String> headers) {
byte[] fetched = null;
try {
long start = System.currentTimeMillis();
WSResponse downloadResp = download(pp, source, headers);
if (downloadResp.getStatus() == HttpURLConnection.HTTP_OK) {
fetched = downloadResp.asByteArray();
log.debug("fetchBytes: pp={}, time-taken={} (ms) to " +
"read {} bytes from source={}", pp,
(System.currentTimeMillis() - start),
fetched.length, source);
} else {
log.debug("fetchBytes: pp={}, failed status={}, " +
"from source={}", pp, downloadResp.getStatus(), source);
}
} catch(Exception bex) {
log.warn("fetchBytes: failed pp={}, from source={}, ex={}",
pp, source, bex);
}
return fetched;
}
public String fetchText(PitchParams pp,
String source,
Map<String,String> headers) {
byte[] fetched = fetchBytes(pp, source, headers);
if(fetched != null)
return new String(fetched, StandardCharsets.UTF_8);
else
return null;
}
/*
* Download file from HTTP(s) source url.
*/
private WSResponse download(PitchParams pp,
String source,
Map<String,String> headers) {
WSResponse downloadResp = null;
try {
log.debug("download: pp={}, source={}", pp, source);
final long start = System.currentTimeMillis();
final WSRequest downloadReq = ws.url(source);
downloadReq.setHeader(API_CACHE_CONTROL, API_NO_CACHE);
headers.forEach((k,v) -> {
downloadReq.setHeader(k, v);
});
downloadResp =
downloadReq.get().toCompletableFuture().get();
} catch (Exception dex) {
log.warn("download: failed pp={}, from source={}, ex={}",
pp, source, dex);
}
return downloadResp;
}
private static final String API_HEADER_AUTH = "Authorization";
private static final String API_HEADER_TOKEN = "token ";
private static final String API_CACHE_CONTROL = "Cache-Control";
private static final String API_NO_CACHE = "no-cache";
}

View File

@ -1,78 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2017 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import java.util.List;
import java.util.Collections;
import java.util.Optional;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import java.nio.charset.StandardCharsets;
/*
* Markdown Delimiter Parameter Parser.
*/
public class DelimParams {
private String delimiter;
private List<NameValuePair> params = Collections.emptyList();
private DelimParams(String delimiter) {
this.delimiter = delimiter;
if(delimiter != null && delimiter.contains(QUERY_ON_DELIM)) {
int queryIndex = delimiter.indexOf(QUERY_ON_DELIM) + 1;
String delimQuery = delimiter.substring(queryIndex);
this.params =
URLEncodedUtils.parse(delimQuery, StandardCharsets.UTF_8);
}
}
public static DelimParams build(String delimiter) {
return new DelimParams(delimiter);
}
public String get(String param) {
return get(param, null);
}
public String get(String param, String defaultValue) {
if(params != null) {
Optional<NameValuePair> match =
params.stream()
.filter(nvp -> nvp.getName().equals(param))
.findFirst();
return match.isPresent() ? match.get().getValue() : defaultValue;
} else {
return defaultValue;
}
}
public static final String QUERY_ON_DELIM = "?";
}

View File

@ -1,697 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import com.gitpitch.git.GRS;
import com.gitpitch.git.vendors.*;
import com.gitpitch.models.GitRepoModel;
import com.gitpitch.policies.Runtime;
import com.gitpitch.utils.PitchParams;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import play.Logger;
import play.Logger.ALogger;
/*
* Rendering model for views.Slideshow.scala.html.
*/
public class GitRepoRenderer {
private final Logger.ALogger log = Logger.of(this.getClass());
private final PitchParams _pp;
private final GitRepoModel _grm;
private final Runtime runtime;
private List<GRS> _grsServices;
/*
* Relative URLs for view components.
*/
private String _slideshowBase;
private String _slideshowURL;
private String _markdownURL;
/*
* Absolute URLs for Git page links.
*/
private String _orgHub;
private String _repoHub;
private String _starHub;
private String _forkHub;
private GitRepoRenderer(PitchParams pp, List<GRS> grsServices) {
this(pp, null, null, grsServices);
}
private GitRepoRenderer(PitchParams pp,
GitRepoModel grm,
Runtime runtime,
List<GRS> grsServices) {
this._pp = pp;
this._grm = grm;
this.runtime = runtime;
this._grsServices = grsServices;
if (grm != null) {
/*
* Initialize properties based on valid repository
* data returned on Git Git API as GitRepoModel, if exists.
*/
this._slideshowURL =
com.gitpitch.controllers.routes.PitchController
.slideshow(_grm.owner(),
_grm.name(),
_pp.branch,
_pp.grs,
_pp.theme,
_pp.pitchme,
_pp.notes, null, null, null).toString();
this._markdownURL = com.gitpitch.controllers.routes.PitchController
.markdown(_pp.grs,
_grm.owner(),
_grm.name(),
_pp.branch,
_pp.pitchme).toString();
Optional<GRS> grso =
this._grsServices.stream()
.filter(grs -> grs.getType().equals(_pp.grs))
.findFirst();
Optional<GRS> grsoDefault =
this._grsServices.stream()
.filter(grs -> grs.isDefault())
.findFirst();
String grsSite = null;
if(grso.isPresent()) {
grsSite = grso.get().getSite();
} else {
if(grsoDefault.isPresent())
grsSite = grsoDefault.get().getSite();
else
grsSite = GRS_GITHUB_COM;
}
this._orgHub = new StringBuffer(grsSite).append(_grm.owner())
.toString();
this._repoHub =
new StringBuffer(_orgHub).append(SLASH)
.append(this._grm.name())
.toString();
switch(_pp.grs) {
case GitHub.TYPE:
this._starHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_GITHUB_STARS)
.toString();
this._forkHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_GITHUB_FORKS)
.toString();
break;
case GitLab.TYPE:
this._starHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_GITLAB_STARS)
.toString();
this._forkHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_GITLAB_FORKS)
.append(_pp.branch)
.toString();
break;
case BitBucket.TYPE:
this._starHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_BITBUCKET_STARS)
.toString();
this._forkHub =
new StringBuffer(this._repoHub).append(SLASH)
.append(GRS_BITBUCKET_FORKS)
.toString();
break;
default:
this._starHub = "#";
this._forkHub = "#";
break;
}
} else {
/*
* Initialize properties to non-null defaults as valid Git
* repository data is not available.
*/
this._slideshowBase = HTTP_HASH;
this._slideshowURL = HTTP_HASH;
this._orgHub = HTTP_HASH;
this._repoHub = HTTP_HASH;
this._starHub = HTTP_HASH;
this._forkHub = HTTP_HASH;
}
}
public static GitRepoRenderer build(PitchParams pp,
GitRepoModel grm,
Runtime runtime,
List<GRS> grsServices) {
return new GitRepoRenderer(pp, grm, runtime, grsServices);
}
/*
* Return PitchParams on this GitRepoRenderer.
*/
public PitchParams params() {
return _pp;
}
/*
* Return GitRepoModel on this GitRepoRenderer.
*/
public GitRepoModel model() {
return _grm;
}
/*
* Return Git {user} name.
*/
public String user() {
return _pp.user;
}
/*
* Return Git {repo} name.
*/
public String repo() {
return _pp.repo;
}
/*
* Return Git {branch} name.
*/
public String branch() {
return _pp.branch;
}
/*
* Return Git {pitchme} path.
*/
public String pitchme() {
return (_pp.pitchme != null) ?
_pp.pitchme.replaceAll("/", ".") : PITCHME;
}
/*
* Return pitch slideshow theme.
*/
public String theme() {
return _pp.theme;
}
/*
* Return pitch slideshow grs.
*/
public String grs() {
return _pp.grs;
}
/*
* Return true is branch is GIT_MASTER.
*/
public boolean isMaster() {
return _pp.isMaster();
}
/*
* Return pitch slideshow theme.css.
*/
public String themeCSS() {
return _pp.theme + CSS;
}
/*
* Return relative URL to slideshow.
*/
public String slideshowURL() {
return _slideshowURL;
}
/*
* Return relative URL to slideshow.
*/
public String slideshowURL(String theme) {
return com.gitpitch.controllers.routes.PitchController
.slideshow(_grm.owner(),
_grm.name(),
_pp.branch,
_pp.grs,
theme,
_pp.pitchme,
_pp.notes, null, null, null).toString();
}
/*
* Return absolute URL to slideshow.
*/
public String slideshowAbs() {
return com.gitpitch.controllers.routes.PitchController
.slideshow(_pp.user,
_pp.repo,
_pp.branch,
_pp.grs,
_pp.theme,
_pp.pitchme,
_pp.notes, null, null, null).absoluteURL(isEncrypted(),
hostname());
}
/*
* Return URL to oEmbed discovery link for slideshow.
*/
public String oembed(String url, String format) {
log.debug("oembed: [ {}, {} ]", url, format);
return com.gitpitch.controllers.routes.PitchController.oembed(url,
format, null, null, null, null, null)
.absoluteURL(isEncrypted(), hostname());
}
/*
* Return relative URL to PITCHME.md markdown.
*/
public String markdownURL() {
return _markdownURL;
}
/*
* Return https://{grs}/{user}.
*/
public String orgHub() {
return _orgHub;
}
/*
* Return https://{grs}/{user}/{repo}.
*/
public String repoHub() {
return _repoHub;
}
/*
* Return https://{grs}/{user}/{repo}/tree/{branch}
*/
public String branchHub(PitchParams pp) {
String branchHub = "#";
switch(pp.grs) {
case GRS_GITHUB:
case GRS_GITLAB:
case GRS_GITBUCKET:
branchHub = _repoHub + GIT_TREE + pp.branch;
break;
case GRS_BITBUCKET:
branchHub = _repoHub + GIT_SRC + pp.branch;
break;
case GRS_GITEA:
branchHub = _repoHub + GIT_SRC_BRANCH + pp.branch;
break;
case GRS_GOGS:
branchHub = _repoHub + GIT_SRC + pp.branch;
break;
}
return branchHub;
}
/*
* Return https://{grs}/{user}/{repo}/blob/{branch}/{pitchme}
*/
public String pitchHub(PitchParams pp) {
String pitchPath =
(pp.pitchme != null) ? (pp.branch + SLASH + pp.pitchme) : pp.branch;
String pitchHub = "#";
switch(pp.grs) {
case GRS_GITHUB:
case GRS_GITLAB:
case GRS_GITBUCKET:
pitchHub = _repoHub + GIT_BLOB + pitchPath + DEFAULT_PITCHME;
break;
case GRS_BITBUCKET:
pitchHub = _repoHub + GIT_SRC + pitchPath + DEFAULT_PITCHME;
break;
case GRS_GITEA:
pitchHub = _repoHub + GIT_SRC_BRANCH + pitchPath + DEFAULT_PITCHME;
break;
case GRS_GOGS:
pitchHub = _repoHub + GIT_SRC + pitchPath + DEFAULT_PITCHME;
break;
}
return pitchHub;
}
/*
* Return https://github.com/{user}/{repo}/stargazers.
*/
public String starHub() {
return _starHub;
}
/*
* Return https://github.com/{user}/{repo}/network.
*/
public String forkHub() {
return _forkHub;
}
/*
* Return number of Git repository stargazers.
*/
public int stargazers() {
return (_grm != null) ? _grm.stargazers() : 0;
}
/*
* Return number of Git repository forks.
*/
public int forks() {
return (_grm != null) ? _grm.forks() : 0;
}
/*
* Return Git repository language.
*/
public String repoLang() {
String repoLang = null;
if(_grm != null) {
if(_grm.lang() != null && _grm.lang().length() > 0) {
repoLang = _grm.lang();
}
}
return repoLang;
}
/*
* Return true if ViewModel represents a valid
* repository on Git.
*/
public boolean isValid() {
return _grm != null;
}
/*
* Return the "best fit" repo language or branch
* name when rendering the presentation.
*/
public String displayLangOrBranch() {
if (!isValid()) {
return _pp.branch;
} else if (isMaster() && repoLang() != null) {
return repoLang();
} else {
return _pp.branch;
}
}
public String pageLink() {
return pageLink(false);
}
public String pageLink(boolean absolute) {
return pageLink(absolute, null);
}
public String pageLink(boolean absolute, String grs) {
grs = (grs != null) ? grs : _pp.grs;
if (absolute)
return com.gitpitch.controllers.routes.PitchController
.slideshow(_pp.user,
_pp.repo,
_pp.branch,
grs,
_pp.theme,
_pp.pitchme,
_pp.notes,
null, null, null)
.absoluteURL(isEncrypted(),
hostname());
else
return com.gitpitch.controllers.routes.PitchController
.slideshow(_pp.user,
_pp.repo,
_pp.branch,
grs,
_pp.theme,
_pp.pitchme,
_pp.notes, null, null, null).toString();
}
public String pageLinkWithTheme(String theme) {
return com.gitpitch.controllers.routes.PitchController
.slideshow(_pp.user,
_pp.repo,
_pp.branch,
_pp.grs,
theme,
_pp.pitchme,
_pp.notes,
null, null, null).toString();
}
public String printLink() {
return com.gitpitch.controllers.routes.PitchController.print(_pp.grs,
_pp.user,
_pp.repo,
_pp.branch,
_pp.theme,
_pp.pitchme,
_pp.notes).toString();
}
public String printBrowserLink() {
return com.gitpitch.controllers.routes.PitchController
.slideshow(_pp.user,
_pp.repo,
_pp.branch,
_pp.grs,
_pp.theme,
_pp.pitchme,
_pp.notes,
null,
"false",
"true").toString();
}
public String offlineLink() {
return com.gitpitch.controllers.routes.PitchController.offline(_pp.grs,
_pp.user,
_pp.repo,
_pp.branch,
_pp.theme,
_pp.pitchme,
_pp.notes).toString();
}
public String twitterLink() {
return new StringBuffer("http://twitter.com/share?text=")
.append("GitPitch presentation...")
.append("&url=")
.append(pageLink(true, null))
.append("&hashtags=gitpitch")
.toString();
}
public String linkedInLink() {
return new StringBuffer("https://www.linkedin.com/shareArticle")
.append("?source=gitpitch")
.append("&mini=true")
.append("&summary=GitPitch%20presentation...")
.append("&title=GitPitch")
.append("&url=")
.append(pageLink(true, null))
.toString();
}
public String pageEmbed() {
return new StringBuffer(EMBED_OPEN)
.append(pageLink(true))
.append(EMBED_CLOSE)
.toString();
}
public String pageBadge() {
return new StringBuffer(BADGE_OPEN)
.append(pageLink(true))
.append(BADGE_CLOSE)
.toString();
}
public String getGRS(PitchParams pp) {
String grsName = null;
for(GRS grs : _grsServices) {
if(grs.getType().equals(pp.grs)) {
grsName = grs.getName();
}
}
return grsName;
}
public List<GRS> listGRS() {
return _grsServices;
}
public String getGRSIcon(PitchParams pp) {
String icon = GIT_DEFAULT_ICON;
switch(pp.grs) {
case "github":
icon = GITHUB_ICON;
break;
case "gitlab":
icon = GITLAB_ICON;
break;
case "bitbucket":
icon = BITBUCKET_ICON;
break;
}
return icon;
}
public List<String> listThemes() {
List<String> themesList =
runtime.configStringList("gitpitch.revealjs.themes");
if(themesList == null || themesList.isEmpty()) {
themesList = DEPLOY_THEMES;
}
return themesList;
}
public String pageDescription() {
if(model() != null && model().description() != null) {
return model().description();
} else {
return AS_DESCR;
}
}
/*
* Return string representation of ViewModel.
*/
public String toString() {
return _slideshowURL;
}
private boolean isEncrypted() {
return runtime.configBool("gitpitch.https");
}
private String hostname() {
return runtime.config("gitpitch.hostname");
}
private static final String GIT_MASTER = "master";
private static final String GIT_TREE = "/tree/";
private static final String GIT_BLOB = "/blob/";
private static final String GIT_SRC = "/src/";
private static final String GIT_SRC_BRANCH = "/src/branch/";
private static final String CSS = ".css";
private static final String MARKDOWN = "/pitchme/markdown/";
private static final String SLASH = "/";
private static final String QMARK_BRANCH = "?b=";
private static final String QMARK_THEME = "&t=";
private static final String HTTP_HASH = "#";
private static final String EMBED_OPEN =
"<iframe width='770' height='515' src='";
private static final String EMBED_CLOSE =
"' frameborder='0' allowfullscreen></iframe>";
private static final String BADGE_OPEN =
"[![GitPitch](https://gitpitch.com/assets/badge.svg)](";
private static final String BADGE_CLOSE = ")";
private static final String PITCHME = "PITCHME.md";
private static final String DEFAULT_PITCHME = "/PITCHME.md";
private static final String DEFAULT_THEME = "white";
private static final List<String> THEMES = Arrays.asList(DEFAULT_THEME,
"beige", "black", "moon", "night", "sky", "white");
private static final String GRS_GITHUB_COM = "https://github.com/";
private static final String GRS_GITHUB_STARS = "stargazers";
private static final String GRS_GITHUB_FORKS = "network";
private static final String GRS_GITLAB_STARS = "activity";
private static final String GRS_GITLAB_FORKS = "graphs/";
private static final String GRS_BITBUCKET_STARS = "commits/all";
private static final String GRS_BITBUCKET_FORKS = "branches";
private static final String GITHUB_ICON =
"<span class='octicon octicon-mark-github'></span>";
private static final String GITLAB_ICON =
"<i class='fa fa-gitlab' aria-hidden='true'></i>";
private static final String BITBUCKET_ICON =
"<i class='fa fa-bitbucket' aria-hidden='true'></i>";
private static final String GIT_DEFAULT_ICON =
"<i class='fa fa-git-square' aria-hidden='true'></i>";
private static final String GRS_GITHUB = "github";
private static final String GRS_GITLAB = "gitlab";
private static final String GRS_BITBUCKET = "bitbucket";
private static final String GRS_GITBUCKET = "gitbucket";
private static final String GRS_GITEA = "gitea";
private static final String GRS_GOGS = "gogs";
private static final String AS_DESCR =
"Markdown Presentation powered by GitPitch.";
private static final List<String> DEPLOY_THEMES =
Arrays.asList("black", "moon", "night", "beige", "sky", "white");
}

View File

@ -1,134 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import com.gitpitch.git.GRSService;
import com.gitpitch.models.SlideshowModel;
import com.gitpitch.services.DiskService;
import play.Logger;
import java.nio.file.Path;
import java.util.Optional;
/*
* Rendering model for PITCHME.md markdown.
*/
public class MarkdownRenderer {
private final Logger.ALogger log = Logger.of(this.getClass());
private final PitchParams _pp;
private final Optional<SlideshowModel> _ssm;
private GRSService grsService;
private DiskService diskService;
private MarkdownRenderer(PitchParams pp,
Optional<SlideshowModel> ssm,
GRSService grsService,
DiskService diskService) {
this._pp = pp;
this._ssm = ssm;
this.grsService = grsService;
this.diskService = diskService;
}
public static MarkdownRenderer build(PitchParams pp,
Optional<SlideshowModel> ssm,
GRSService grsService,
DiskService diskService) {
return new MarkdownRenderer(pp, ssm, grsService, diskService);
}
public PitchParams pp() {
return _pp;
}
public Optional<SlideshowModel> ssm() {
return _ssm;
}
public String gitRawBase() {
return grsService.raw(_pp);
}
public Path filePath(String filename) {
return diskService.asPath(_pp, filename);
}
public boolean hasLogo() {
if (_ssm.isPresent()) {
SlideshowModel model = _ssm.get();
log.debug("hasLogo: ssm found, hasLogo={}", model.hasLogo());
return model.hasLogo();
} else {
log.debug("hasLogo: ssm not found, so no logo.");
return false;
}
}
public String fetchLogo() {
if (_ssm.isPresent()) {
SlideshowModel model = _ssm.get();
return model.fetchLogo();
} else {
return "#";
}
}
public boolean hasLogoPosition() {
if (_ssm.isPresent()) {
SlideshowModel model = _ssm.get();
log.debug("hasLogoPosition: ssm found, hasLogoPosition={}", model.hasLogoPosition());
return model.hasLogoPosition();
} else {
log.debug("hasLogoPosition: ssm not found, so no logoPosition.");
return false;
}
}
public String fetchLogoPosition() {
if (_ssm.isPresent()) {
SlideshowModel model = _ssm.get();
return model.fetchLogoPosition();
} else {
return "#";
}
}
}

View File

@ -1,79 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2017 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
/*
* GitPitch URL utility parser.
*/
public class PitchLink {
public String url;
public String user = UNDEFINED;
public String repo = UNDEFINED;
public String branch = DEFAULT_BRANCH;
public String grs = DEFAULT_GRS;
private PitchLink(String url) {
this.url = url;
}
private PitchLink(String url,
String user,
String repo,
String branch,
String grs) {
this.url = url;
this.user = user;
this.repo = repo;
this.branch = branch;
this.grs = grs;
}
public static PitchLink build(String url) {
try {
URL urlo = new URL(url);
String path = urlo.getPath();
String[] paths = path.split(SLASH);
String uPath = paths[1];
String rPath = paths[2];
String bPath = (paths.length == 4) ? paths[3] : DEFAULT_BRANCH;
String query = urlo.getQuery();
String gPath = DelimParams.build(query).get(GRS, DEFAULT_GRS);
return new PitchLink(url, uPath, rPath, bPath, gPath);
} catch(Exception ex) {
return new PitchLink(url);
}
}
private final static String DEFAULT_BRANCH = "master";
private final static String DEFAULT_GRS = "github";
private final static String UNDEFINED = "undefined";
private final static String GRS = "grs";
private final static String SLASH = "/";
}

View File

@ -1,269 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import java.util.Arrays;
import java.util.List;
/*
* GitPitch API Parameters Command Object.
*/
public class PitchParams {
public String user;
public String repo;
public String branch;
public String theme;
public String notes;
public String grs;
public String pitchme;
private PitchParams(String grs,
String user,
String repo) {
this(grs, user, repo, null);
}
private PitchParams(String grs,
String user,
String repo,
String branch) {
this(grs, user, repo, branch, null);
}
private PitchParams(String grs,
String user,
String repo,
String branch,
String theme) {
this(grs, user, repo, branch, theme, null);
}
private PitchParams(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme) {
this(grs, user, repo, branch, theme, pitchme, null);
}
private PitchParams(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String notes) {
this.grs = grs;
this.user = user;
this.repo = repo;
this.branch = (branch != null) ? branch : DEFAULT_BRANCH;
if (DEFAULT_THEMES.contains(theme))
this.theme = theme;
else
this.theme = DEFAULT_THEME;
this.pitchme = pitchme;
this.notes = notes;
}
public static PitchParams build(String grs,
String user,
String repo) {
return new PitchParams(grs, user, repo);
}
public static PitchParams build(String grs,
String user,
String repo,
String branch) {
return new PitchParams(grs, user, repo, branch);
}
public static PitchParams build(String grs,
String user,
String repo,
String branch,
String theme) {
return new PitchParams(grs, user, repo, branch, theme);
}
public static PitchParams build(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme) {
return new PitchParams(grs, user, repo, branch, theme, pitchme);
}
public static PitchParams build(String grs,
String user,
String repo,
String branch,
String theme,
String pitchme,
String notes) {
return new PitchParams(grs, user, repo, branch, theme, pitchme, notes);
}
public static boolean isDarkTheme(String theme) {
return DARK_THEMES.contains(theme);
}
public static boolean isLightTheme(String theme) {
return LIGHT_THEMES.contains(theme);
}
public static String fetchThemeCSS(String theme) {
return new StringBuffer(theme).append(DOT_CSS)
.toString();
}
public String MD() {
return (pitchme != null) ?
pitchme + SLASH + PITCHME_MD : PITCHME_MD;
}
public String YAML() {
return (pitchme != null) ?
pitchme + SLASH + PITCHME_YAML : PITCHME_YAML;
}
public String PDF() {
return (pitchme != null) ?
pitchme + SLASH + PITCHME_PDF : PITCHME_PDF;
}
public boolean isMaster() {
return GIT_MASTER.equals(this.branch);
}
public boolean isLongLived() {
return USER_GITPITCH.equals(this.user);
}
public boolean darkTheme() {
return DARK_THEMES.contains(this.theme);
}
public boolean lightTheme() {
return LIGHT_THEMES.contains(this.theme);
}
public String pretty() {
StringBuffer pretty =
new StringBuffer(SLASH).append(grs)
.append(SLASH)
.append(user)
.append(SLASH)
.append(repo);
if(!branch.equals(GIT_MASTER)) {
pretty.append(SLASH).append(branch);
}
return pretty.toString();
}
public String atPretty() {
String pretty = pretty().substring(1);
return new StringBuffer(AT).append(pretty).toString();
}
public String toString() {
return new StringBuffer(SLASH).append(grs)
.append(SLASH)
.append(user)
.append(SLASH)
.append(repo)
.append(SLASH)
.append(branch)
.append(" [ ")
.append(theme)
.append(", ")
.append(pitchme)
.append(" ]")
.toString();
}
public String asLogo() {
return new StringBuffer(user).append(SPACED_SLASH)
.append(repo)
.toString();
}
public String asTitle() {
return new StringBuffer("[ GitPitch ] ")
.append(user)
.append(SLASH)
.append(repo)
.append(SLASH)
.append(branch)
.toString();
}
public boolean isValidTheme(String themeName) {
return DEFAULT_THEMES.contains(themeName);
}
public boolean isValidPosition(String logoPosition) {
return LOGO_POSITIONS.contains(logoPosition);
}
public static final String PITCHME_MD = "PITCHME.md";
public static final String PITCHME_YAML = "PITCHME.yaml";
public static final String PITCHME_PDF = "PITCHME.pdf";
public static final String DEFAULT_THEME = "white";
public static final String DEFAULT_THEME_CSS = "white.css";
public static final String DEFAULT_LOGO_POSITION = "top-left";
private static final List<String> LOGO_POSITIONS =
Arrays.asList("top-left", "top-right", "bottom-left", "bottom-right");
private static final List<String> DARK_THEMES =
Arrays.asList("black", "moon", "night");
private static final List<String> LIGHT_THEMES =
Arrays.asList("beige", "sky", "white");
private static final List<String> DEFAULT_THEMES =
Arrays.asList("black", "moon", "night", "beige", "sky", "white");
private static final String DOT_CSS = ".css";
private final String USER_GITPITCH = "gitpitch";
private final String GIT_MASTER = "master";
private final String DEFAULT_BRANCH = "master";
private final String PARAM_BRANCH = "?b=";
private final String PARAM_THEME = "&t=";
private final String PARAM_NOTES = "&n=";
private final String SLASH = "/";
private final String SPACED_SLASH = " / ";
private final String AT = "@ ";
}

View File

@ -1,67 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import com.gitpitch.git.GRS;
import com.gitpitch.utils.PitchParams;
import java.util.StringJoiner;
/*
* GitHub RFE issue support utility.
*/
public final class RFE {
/*
* Build message that offers the user a
* chance to submit a Feature Request (Issue)
* against the repo identified by PitchParams.
*/
public static String master(PitchParams pp, GRS grs) {
String newIssue = grs.getSite() +
pp.user + "/" + pp.repo + "/issues/new";
StringBuffer buf = new StringBuffer();
buf.append("<span style=\"font-size:1.1em\">Presentation 404</span><br><br>")
.append("\n\n")
.append("<span style=\"font-size:0.9em\">")
.append("PITCHME.md not found in repo on ")
.append(grs.getName())
.append(".</span>");
return buf.toString();
}
public static String branch(PitchParams pp, GRS grs) {
return new StringBuffer("<span style=\"font-size:1.1em\">")
.append("Presentation 404</span><br><br>")
.append("\n\n")
.append("<span style=\"font-size:0.9em\">")
.append("PITCHME.md not found in branch on ")
.append(grs.getName())
.append(".</span>")
.toString();
}
}

View File

@ -1,498 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2016 David Russell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.gitpitch.utils;
import com.gitpitch.git.GRSService;
import com.gitpitch.services.DiskService;
import org.yaml.snakeyaml.Yaml;
import play.Logger;
import play.Logger.ALogger;
import java.io.File;
import java.io.FileReader;
import java.nio.file.Path;
import java.util.*;
/*
* PITCHME.yaml options utility.
*/
public final class YAMLOptions {
private final static Logger.ALogger log =
Logger.of("com.gitpitch.utils.YAMLOptions");
private final Map<String, String> _yProps;
private final GRSService grsService;
private YAMLOptions(Map<String, String> yProps,
GRSService grsService) {
this._yProps = yProps;
this.grsService = grsService;
}
public static YAMLOptions build(PitchParams pp,
GRSService grsService,
DiskService diskService) {
YAMLOptions yOpts = null;
try {
/*
* Instantiate YAML parser.
*/
Yaml yaml = new Yaml();
/*
* Build path to PITCHME_YAML on disk.
*/
Path yPath = diskService.asPath(pp, PITCHME_YAML);
File yFile = yPath.toFile();
if (yFile.exists()) {
/*
* Use YAML parser to transform YAML properties to Map.
*/
Map<String, String> yProps =
(Map<String, String>) yaml.load(new FileReader(yPath.toFile()));
/*
* Handle PITCHME.yaml empty file without properites.
*/
if (yProps == null) {
yProps = new HashMap<String, String>();
}
log.debug("build: pp={}, props={}", pp, yProps);
yOpts = new YAMLOptions(yProps, grsService);
} else {
log.debug("build: pp={}, yaml not found={}", yFile);
}
} catch (Exception yex) {
log.warn("build: pp={}, parsing YAML ex={}", pp, yex);
} finally {
return yOpts;
}
}
public boolean fixedTheme(PitchParams pp) {
return _yProps.get(THEME_OPTION) != null;
}
public String fetchTheme(PitchParams pp) {
String theme = _yProps.get(THEME_OPTION);
return pp.isValidTheme(theme) ? theme : pp.theme;
}
public String fetchLayout(PitchParams pp) {
String layout = _yProps.get(LAYOUT_OPTION);
return isValidLayout(layout) ? layout : DEFAULT_LAYOUT;
}
private boolean isValidLayout(String layoutName) {
return DEFAULT_LAYOUTS.contains(layoutName);
}
public boolean isLeftLayout(PitchParams pp) {
return fetchLayout(pp).contains(LEFT);
}
public boolean isRightLayout(PitchParams pp) {
return fetchLayout(pp).contains(RIGHT);
}
public boolean isTopLayout(PitchParams pp) {
return fetchLayout(pp).contains(TOP);
}
public String fetchThemeCSS(PitchParams pp) {
return new StringBuffer(fetchTheme(pp)).append(DOT_CSS)
.toString();
}
public boolean hasThemeOverride(PitchParams pp) {
return (_yProps.get(THEME_OVERRIDE_OPTION) != null);
}
public String fetchThemeOverride(PitchParams pp) {
String overridePath = _yProps.get(THEME_OVERRIDE_OPTION);
if (isAbsolute(overridePath)) {
return overridePath;
} else {
return grsService.raw(pp, overridePath);
}
}
public boolean hasLogo() {
return (_yProps.get(LOGO_OPTION) != null);
}
public String fetchLogo(PitchParams pp) {
String logoPath = _yProps.get(LOGO_OPTION);
if (isAbsolute(logoPath)) {
return logoPath;
} else {
return grsService.raw(pp, logoPath);
}
}
public boolean hasLogoPosition() {
return (_yProps.get(LOGO_POSITION_OPTION) != null);
}
public String fetchLogoPosition(PitchParams pp) {
String logoPosition = _yProps.get(LOGO_POSITION_OPTION);
return pp.isValidPosition(logoPosition) ? logoPosition : pp.DEFAULT_LOGO_POSITION;
}
public boolean hasImageBg() {
return (_yProps.get(IMAGE_BG_OPTION) != null);
}
public String fetchImageBg(PitchParams pp) {
String imgBgPath = _yProps.get(IMAGE_BG_OPTION);
if (isAbsolute(imgBgPath)) {
return imgBgPath;
} else {
return grsService.raw(pp, imgBgPath);
}
}
public String fetchImageBgSize(PitchParams pp) {
String bgSize = _yProps.get(IMAGE_BG_SIZE_OPTION);
if (bgSize == null) {
return DEFAULT_BG_SIZE;
} else {
return bgSize;
}
}
public String fetchImageBgColor(PitchParams pp) {
String bgColor = _yProps.get(IMAGE_BG_COLOR_OPTION);
if (bgColor == null) {
return DEFAULT_BG_COLOR;
} else {
return bgColor;
}
}
public String fetchImageBgPosition(PitchParams pp) {
String bgPosition = _yProps.get(IMAGE_BG_POSITION_OPTION);
if (bgPosition == null) {
return DEFAULT_BG_POSITION;
} else {
return bgPosition;
}
}
public String fetchImageBgRepeat(PitchParams pp) {
String bgRepeat = _yProps.get(IMAGE_BG_REPEAT_OPTION);
if (bgRepeat == null) {
return DEFAULT_BG_REPEAT;
} else {
return bgRepeat;
}
}
public String fetchTransition(PitchParams pp) {
String transition = _yProps.get(TRANSITION_OPTION);
if (TRANSITIONS.contains(transition))
return transition;
else
return DEFAULT_TRANSITION;
}
public String fetchControlsLayout(PitchParams pp) {
String layout = _yProps.get(CONTROLS_LAYOUT_OPTION);
if (CONTROL_LAYOUTS.contains(layout))
return layout;
else
return DEFAULT_CONTROLS_LAYOUT;
}
public Integer fetchAutoSlide(PitchParams pp) {
return fetchIntegerOption(pp, AUTOSLIDE_OPTION);
}
public Boolean fetchVerticalCenter(PitchParams pp) {
return fetchBooleanOption(pp, VERTICAL_CENTER, true);
}
public Boolean fetchLoop(PitchParams pp) {
return fetchBooleanOption(pp, LOOP_OPTION);
}
public Boolean fetchRemoteControl(PitchParams pp) {
return fetchBooleanOption(pp, REMOTE_CONTROL_OPTION);
}
public Integer fetchRemoteControlPrevKey(PitchParams pp) {
return fetchIntegerOption(pp, REMOTE_CONTROL_PREVKEY_OPTION);
}
public Integer fetchRemoteControlNextKey(PitchParams pp) {
return fetchIntegerOption(pp, REMOTE_CONTROL_NEXTKEY_OPTION);
}
public Boolean fetchRTL(PitchParams pp) {
return fetchBooleanOption(pp, RTL_OPTION);
}
public Boolean fetchShuffle(PitchParams pp) {
return fetchBooleanOption(pp, SHUFFLE_OPTION);
}
public Boolean fetchMouseWheel(PitchParams pp) {
return fetchBooleanOption(pp, MOUSE_WHEEL_OPTION);
}
public Boolean fetchCharts(PitchParams pp) {
return fetchBooleanOption(pp, CHARTS_OPTION);
}
public Boolean mathEnabled(PitchParams pp) {
String mathjax = _yProps.get(MATHJAX_OPTION);
return (mathjax != null);
}
public Boolean fetchHistory(PitchParams pp) {
return fetchBooleanOption(pp, HISTORY_OPTION, true);
}
public Boolean fetchSlideNumber(PitchParams pp) {
return fetchBooleanOption(pp, SLIDE_NUMBER_OPTION);
}
public String mathConfig(PitchParams pp) {
return mathEnabled(pp) ?
_yProps.get(MATHJAX_OPTION) : MATHJAX_DEFAULT;
}
public Boolean highlightEnabled(PitchParams pp) {
return (_yProps.get(HIGHLIGHT_OPTION) != null) ? true : false;
}
public String fetchHighlight(PitchParams pp) {
return highlightEnabled(pp) ?
(_yProps.get(HIGHLIGHT_OPTION) + ".css") :
defaultHighlight(pp);
}
public boolean hasFootnote(PitchParams pp) {
return _yProps.get(FOOTNOTE_OPTION) != null;
}
public String fetchFootnote(PitchParams pp) {
return _yProps.get(FOOTNOTE_OPTION);
}
public boolean hasGAToken(PitchParams pp) {
return (_yProps.get(GATOKEN_OPTION) != null);
}
public String fetchGAToken(PitchParams pp) {
return _yProps.get(GATOKEN_OPTION);
}
public boolean hasHorzDelim(PitchParams pp) {
return _yProps.get(HSLIDE_DELIM) != null;
}
public String fetchHorzDelim(PitchParams pp) {
return _yProps.get(HSLIDE_DELIM);
}
public String fetchHorzDelimRegExp(PitchParams pp) {
return _yProps.get(HSLIDE_DELIM_REGEXP);
}
public boolean hasVertDelim(PitchParams pp) {
return _yProps.get(VSLIDE_DELIM) != null;
}
public String fetchVertDelim(PitchParams pp) {
return _yProps.get(VSLIDE_DELIM);
}
public String fetchVertDelimRegExp(PitchParams pp) {
return _yProps.get(VSLIDE_DELIM_REGEXP);
}
public String fetchRevealVersion(PitchParams pp) {
return _yProps.get(REVEALJS_VERSION);
}
public Boolean published(PitchParams pp) {
return fetchBooleanOption(pp, PUBLISHED_OPTION);
}
public Boolean printFrags(PitchParams pp) {
return fetchBooleanOption(pp, PRINT_FRAGS_OPTIONS);
}
private Boolean fetchBooleanOption(PitchParams pp, String option) {
return fetchBooleanOption(pp, option, false);
}
private Boolean fetchBooleanOption(PitchParams pp,
String option, boolean dflt) {
try {
Object optionValue = _yProps.get(option);
if (optionValue instanceof Boolean)
return (Boolean) optionValue;
else if (optionValue instanceof String)
return Boolean.parseBoolean((String) optionValue);
else
return dflt;
} catch (Exception bex) {
return dflt;
}
}
private Integer fetchIntegerOption(PitchParams pp, String option) {
try {
Object optionValue = _yProps.get(option);
if (optionValue instanceof Integer)
return (Integer) optionValue;
else if (optionValue instanceof String)
return Integer.parseInt((String) optionValue);
else
return 0;
} catch (NumberFormatException nfex) {
return 0;
}
}
private String defaultHighlight(PitchParams pp) {
return PitchParams.isDarkTheme(fetchTheme(pp)) ?
HIGHLIGHT_DARK_DEFAULT : HIGHLIGHT_LIGHT_DEFAULT;
}
private boolean isAbsolute(String link) {
return (link != null && link.startsWith(ABS_HTTP));
}
public static final String PITCHME_YAML = "PITCHME.yaml";
public static final String DEFAULT_BG_SIZE = "100% 100%";
public static final String DEFAULT_BG_COLOR = " ";
public static final String DEFAULT_BG_POSITION = "center";
public static final String DEFAULT_BG_REPEAT = " ";
public static final String DEFAULT_TRANSITION = "slide";
public static final String DEFAULT_CONTROLS_LAYOUT = "bottom-right";
public static final String EDGES_CONTROLS_LAYOUT = "edges";
public static final String MATHJAX_DEFAULT = "TeX-MML-AM_CHTML";
public static final String HIGHLIGHT_DARK_DEFAULT = "github-gist.css";
public static final String HIGHLIGHT_LIGHT_DEFAULT = "hybrid.css";
/*
* PITCHME.yaml Supported Options.
*/
private static final String THEME_OPTION = "theme";
private static final String THEME_OVERRIDE_OPTION = "theme-override";
private static final String VERTICAL_CENTER = "vertical-center";
private static final String LOGO_OPTION = "logo";
private static final String LOGO_POSITION_OPTION = "logo-position";
private static final String IMAGE_BG_OPTION = "background";
private static final String IMAGE_BG_SIZE_OPTION = "background-size";
private static final String IMAGE_BG_COLOR_OPTION = "background-color";
private static final String IMAGE_BG_POSITION_OPTION = "background-position";
private static final String IMAGE_BG_REPEAT_OPTION = "background-repeat";
private static final String TRANSITION_OPTION = "transition";
private static final String CONTROLS_LAYOUT_OPTION = "controls-layout";
private static final String AUTOSLIDE_OPTION = "autoslide";
private static final String LOOP_OPTION = "loop";
private static final String REMOTE_CONTROL_OPTION = "remote-control";
private static final String REMOTE_CONTROL_PREVKEY_OPTION =
"remote-control-prevkey";
private static final String REMOTE_CONTROL_NEXTKEY_OPTION =
"remote-control-nextkey";
private static final String RTL_OPTION = "rtl";
private static final String SHUFFLE_OPTION = "shuffle";
private static final String MOUSE_WHEEL_OPTION = "mousewheel";
private static final String MATHJAX_OPTION = "mathjax";
private static final String HIGHLIGHT_OPTION = "highlight";
private static final String FOOTNOTE_OPTION = "footnote";
private static final String GATOKEN_OPTION = "gatoken";
private static final String CHARTS_OPTION = "charts";
private static final String HISTORY_OPTION = "history";
private static final String SLIDE_NUMBER_OPTION = "slide-number";
private static final String REVEALJS_VERSION = "revealjs-version";
private static final String PUBLISHED_OPTION = "published";
private static final String PRINT_FRAGS_OPTIONS = "print-fragments";
private static final String HSLIDE_DELIM = "horz-delim";
private static final String VSLIDE_DELIM = "vert-delim";
private static final String HSLIDE_DELIM_REGEXP = "horz-delim-regexp";
private static final String VSLIDE_DELIM_REGEXP = "vert-delim-regexp";
private static final List<String> TRANSITIONS =
Arrays.asList("default", "none", "fade", "slide",
"convex", "conconcave", "zoom");
private static final List<String> CONTROL_LAYOUTS =
Arrays.asList("bottom-left", "edges");
private static final List<String> MATHJAX_CONFIGS =
Arrays.asList("default",
"TeX-MML-AM_CHTML", "TeX-MML-AM_HTMLorMML",
"TeX-MML-AM_SVG", "TeX-AMS-MML_HTMLorMML",
"TeX-AMS_CHTML", "TeX-AMS_SVG",
"TeX-AMS_HTML", "MML_CHTML", "MML_SVG",
"MML_HTMLorMML", "AM_CHTML", "AM_SVG",
"AM_HTMLorMML", "TeX-AMS-MML_SVG",
"Accessible");
private static final String ABS_HTTP = "http";
private static final String DOT_CSS = ".css";
private static final String LAYOUT_OPTION = "layout";
private static final String DEFAULT_LAYOUT = "center";
private static final List<String> DEFAULT_LAYOUTS =
Arrays.asList("center", "center-left", "center-right", "top", "top-left", "top-right");
private static final String LEFT = "left";
private static final String RIGHT = "right";
private static final String TOP = "top";
}

View File

@ -1,15 +0,0 @@
@(gid: String, deps: com.gitpitch.policies.Dependencies)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>GitPitch - Get the word out about your GitHub projects.</title>
<script src="@deps.jquery(false)/jquery.min.js"></script>
<script src="@deps.gitpitchjs(false)/gist-embed-2.5.min.js"></script>
</head>
<body>
<code data-gist-id="@gid" data-gist-hide-footer="true"></code>
</body>
</html>

View File

@ -1,48 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer, deps: com.gitpitch.policies.Dependencies, offline: Boolean)
<!DOCTYPE html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<body>
<div class="pitch-menu">
<div class="pitch-menu-logo"></div>
<br><br>
<div class="git-box">
<div style="padding-top: 25px; padding-bottom: 10px;">
<span class="git-octicon">
<span class="octicon octicon-git-branch">
<span style="padding-left: 5px;">
Choose Git Service
</span>
</span>
</div>
<hr class="fade-away">
<br>
<ul class="slide-menu-items slide-menu-boxed">
@for(grs <- rndr.listGRS()) {
@if(grs.getType() == rndr.params().grs) {
<li class="home-git slide-menu-item selected">
<a class="active" href='@rndr.pageLink(false, grs.getType())'>@grs.getName()</a>
</li>
} else {
<li class="home-git slide-menu-item">
<a href='@rndr.pageLink(false, grs.getType())'>@grs.getName()</a>
</li>
}
}
</ul>
<br>
</div>
<br><br>
<p>Just add <a href="https://github.com/gitpitch/gitpitch/wiki"
style="text-decoration: none">PITCHME.md</a>.</p>
<p>Then Git-Commit.</p>
<br>
</div>
</body>
</html>

View File

@ -1,114 +0,0 @@
@import com.gitpitch.views.html.frags._
@(rndr: com.gitpitch.utils.GitRepoRenderer,
deps: com.gitpitch.policies.Dependencies,
offline: Boolean,
userAgentIsChrome: Boolean)
<!DOCTYPE html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<body>
<div class="pitch-menu">
<div class="pitch-menu-logo"></div>
<br><br>
<div class="git-box">
<div style="padding-top: 25px; padding-bottom: 10px;">
<span class="git-octicon">
@Html(rndr.getGRSIcon(rndr.params()))
<span style="padding-left: 5px;">
@rndr.getGRS(rndr.params()) Slideshow
</span>
</span>
</div>
<hr class="fade-away">
<table>
<tr>
<td class="git-label">User:</td>
<td><a href="@rndr.orgHub()" target="_blank">
<div class="short-link">@rndr.user()</div>
</a></td>
</tr>
<tr>
<td class="git-label">Repo:</td>
<td><a href="@rndr.repoHub()" target="_blank">
<div class="short-link">@rndr.repo()</div>
</a></td>
</tr>
<tr>
<td class="git-label">Branch:</td>
<td><a href="@rndr.branchHub(rndr.params())" target="_blank">
<div class="short-link">@rndr.branch()</div>
</a></td>
</tr>
<tr>
<td class="git-label">Slides:</td>
<td><a href="@rndr.pitchHub(rndr.params())" target="_blank">
<div class="short-link">@rndr.pitchme()</div>
</a></td>
</tr>
</table>
<hr class="fade-away">
<table style="margin: 0 auto">
<tr>
<td class="git-octicon">
<span class="octicon octicon-star">
<span class="star-fork">
@rndr.stargazers()
</span>
</td>
<td class="git-octicon">
<span class="octicon octicon-repo-forked">
<span class="star-fork">
@rndr.forks()
</span>
</td>
</tr>
</table>
<hr class="fade-away">
@if(!offline) {
<ul>
<li class="slideshow"
title="Download GitPitch presentation for offline use.">
<a href="@rndr.offlineLink()" target="_blank">
<i class="fa fa-download" aria-hidden="true">
</i> Offline Version (.zip)</a>
</li>
<li class="slideshow"
title="Convert GitPitch presentation to PDF doc for printing.">
<a href="@rndr.printLink()" target="_blank">
<i class="fa fa-external-link" aria-hidden="true">
</i> Print Version (.pdf)</a>
</li>
<li class="slideshow">
<a href="@rndr.twitterLink()" target="_blank"
title="Share link to GitPitch presentation on Twitter."
style="padding-left: 0px; padding-right:10px">
<i class="fa fa-twitter" aria-hidden="true">
</i> Twitter</a>
<a href="@rndr.linkedInLink()" target="_blank"
title="Share link to GitPitch presentation on LinkedIn.">
<i class="fa fa-linkedin-square" aria-hidden="true">
</i> LinkedIn</a>
</li>
<li class="slideshow"
title="Open the GitPitch Wiki for detailed How-To help.">
<a href="https://github.com/gitpitch/gitpitch/wiki" target="_blank">
<i class="fa fa-question-circle" aria-hidden="true">
</i> Help</a>
</li>
</ul>
}
<br>
</div>
<br><br>
<p>Promote, Pitch, Or Present</p><p>Absolutely Anything.</p>
<br>
</div>
</body>
</html>

View File

@ -1,46 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<style>
body {
height: 100vh;
min-height: 100vh;
background-image: url(https://gitpitch.com/gp-splash.svg);
background-position: center;
background-size: 60%;
background-color: black;
background-repeat: no-repeat;
}
div.not-found {
color: white;
width: 100%;
text-align: center;
position: absolute;
font-size: 1.2em;
font-family: 'Roboto', sans-serif;
}
div.top {
top: 40px;
text-transform: uppercase;
}
div.bottom {
bottom: 40px;
}
div.byline {
padding-top: 8px;
}
div.gray {
color: #b3b3be;
}
</style>
</head>
<body>
<div class="not-found top">Presentation Not Found
<div class="byline gray">Invalid URL</div>
</div>
<div class="not-found bottom gray">Valid Presentation URL Format
<div class="byline gray">https://gitpitch.com/$user/$repo/$branch</div>
</div>
</body>
</html>

View File

@ -1,17 +0,0 @@
@(pembed: com.gitpitch.oembed.PitchEmbed)
<?xml version="1.0" encoding="UTF-8"?>
<oembed>
<version>1.0</version>
<type>rich</type>
<title>@pembed.title</title>
<author-name>@pembed.author_name</author-name>
<author-url>@pembed.author_url</author-url>
<provider-name>@pembed.provider_name</provider-name>
<provider-url>@pembed.provider_url</provider-url>
<html>@pembed.html</html>
<width type="integer">@pembed.width</width>
<height type="integer">@pembed.height</height>
<thumbnail_url>@pembed.thumbnail_url</thumbnail_url>
<thumbnail_width>@pembed.thumbnail_width</thumbnail_width>
<thumbnail_height>@pembed.thumbnail_height</thumbnail_height>
</oembed>

View File

@ -1,61 +0,0 @@
@import com.gitpitch.views.html.frags._
@(ssm: com.gitpitch.models.SlideshowModel,
rndr: com.gitpitch.utils.GitRepoRenderer,
deps: com.gitpitch.policies.Dependencies,
gpToken: String,
offline: Boolean,
serverPrinting: Boolean,
webPrinting: Boolean)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<title>@ssm.params().asTitle()</title>
<meta content="Markdown Presentation powered by GitPitch." name="description">
<meta content="GitHub, GitLab, Bitbucket, Markdown, Slideshow, Presentation, Developers, PITCHME" name="keywords">
@SlideshowOEmbedDiscovery(rndr)
@SlideshowStyleDependencies(ssm, deps, offline, webPrinting)
@SlideshowRevealCoreOverrides(ssm)
@SlideshowMenuStyle(offline)
@SlideshowNotificationBarStyle(ssm)
@SlideshowCodeFragHighlightStyle()
@SlideshowThemeOverride(ssm)
@SlideshowGoogleAnalytics(ssm, offline, serverPrinting, gpToken)
</head>
<body>
@SlideshowLogo(ssm, offline)
<div class="reveal">
<div class="slides">
@if(offline) {
<section data-markdown="./assets/md/PITCHME.md"
data-separator="@ssm.fetchHorzDelim()"
data-separator-vertical="@ssm.fetchVertDelim()"
data-separator-notes="^Note:"
data-charset="utf-8">
</section>
} else {
<section data-markdown="@ssm.fetchMarkdown()"
data-separator="@ssm.fetchHorzDelim()"
data-separator-vertical="@ssm.fetchVertDelim()"
data-separator-notes="^Note:"
data-charset="utf-8">
</section>
}
</div>
@SlideshowPresentingFooter(ssm, serverPrinting, webPrinting)
</div>
<div class="gp-menu"></div>
@SlideshowPrintFooter(ssm, serverPrinting, webPrinting)
<script src="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/js/reveal.js"></script>
<script src="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/lib/js/head.min.js"></script>
<script src="@deps.jquery(offline)/jquery.min.js"></script>
@SlideshowReveal(ssm, deps, offline, serverPrinting, webPrinting)
@SlideshowNotifications(ssm, serverPrinting, webPrinting)
</body>
</html>

View File

@ -1,70 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer,
deps: com.gitpitch.policies.Dependencies,
fixedTheme: String,
offline: Boolean)
<!DOCTYPE html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<body>
<div class="pitch-menu">
<div class="pitch-menu-logo"></div>
<br><br>
<div class="git-box">
<div style="padding-top: 25px; padding-bottom: 10px;">
<span class="git-octicon">
<span class="octicon octicon-file-media">
<span style="padding-left: 5px;">
Choose Theme
</span>
</span>
</div>
<hr class="fade-away">
<br>
<ul class="slide-menu-items slide-menu-boxed">
@for(theme <- rndr.listThemes()) {
@if(theme == fixedTheme || (fixedTheme == null && theme == rndr.theme())) {
@if(theme == fixedTheme) {
<li class="home-themes slide-menu-item selected fixed-theme">
<a class="active" href='@rndr.pageLinkWithTheme(theme)'>@theme</a>
</li>
} else {
<li class="home-themes slide-menu-item selected">
<a class="active" href='@rndr.pageLinkWithTheme(theme)'>@theme</a>
</li>
}
} else {
@if(fixedTheme != null) {
<li class="home-themes slide-menu-item disabled-theme">
<a href='@rndr.pageLinkWithTheme(theme)'>@theme</a>
</li>
} else {
<li class="home-themes slide-menu-item">
<a href='@rndr.pageLinkWithTheme(theme)'>@theme</a>
</li>
}
}
}
</ul>
<br>
</div>
<br><br>
@if(fixedTheme != null) {
<p><a href="https://github.com/gitpitch/gitpitch/wiki/Slideshow-Settings"
style="text-decoration: none">PITCHME.yaml</a></p>
<p>Fixed theme in use.</p>
</p>
} else {
<p>Use <a href="https://github.com/gitpitch/gitpitch/wiki"
style="text-decoration: none">PITCHME.yaml</a> To</p>
<p>Customize Everything.</p>
}
<br>
</div>
</body>
</html>

View File

@ -1,16 +0,0 @@
@(gaToken: String, gpu: Boolean)
@if(gaToken != null) {
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
@if(gpu) {
ga('create', '@gaToken', 'auto', 'gpu');
ga('gpu.send', 'pageview');
} else {
ga('create', '@gaToken', 'auto');
ga('send', 'pageview');
}
</script>
}

View File

@ -1,75 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer, offline: Boolean)
<nav class="navbar navbar-inverse navbar-fixed-bottom">
<div class="container-fluid">
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@if(offline) {
<p class="navbar-text pull-left"><span style="color: white; font-weight:bold; font-size: 1.3em"> @rndr.getGRS(rndr.params())</span>
</p>
} else {
<li class="dropdown">
<a href="#" class="dropdown-toggle" style="font-size:1.3em; font-weight:bold" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">@rndr.getGRS(rndr.params()) <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">GitPitch Git Services</li>
<li role="separator" class="divider"></li>
@for(grs <- rndr.listGRS()) {
<li><a href='@rndr.pageLink(false, grs.getType())'>@grs.getName()</a></li>
}
</ul>
</li>
<li>
<a href="#popupTheme" role="button" data-toggle="modal-popover" data-placement="top"><i
class="fa fa-paint-brush" aria-hidden="true"> <span style="font-family: Helvetica Neue"
,Helvetica,Arial,sans-serif;">Theme</span>
</i></a>
</li>
<li>
<a href="#popupBadge" role="button" data-toggle="modal-popover" data-placement="top"><i
class="fa fa-shield" aria-hidden="true"> <span style="font-family: Helvetica Neue"
,Helvetica,Arial,sans-serif;">Badge</span>
</i></a>
</li>
<li>
<a href="#popupEmbed" role="button" data-toggle="modal-popover" data-placement="top"><i
class="fa fa-link" aria-hidden="true"> <span style="font-family: Helvetica Neue"
,Helvetica,Arial,sans-serif;">Embed</span>
</i></a>
</li>
<li>
<a href="#popupShare" role="button" data-toggle="modal-popover" data-placement="top"><i
class="fa fa-share" aria-hidden="true"> <span style="font-family: Helvetica Neue"
,Helvetica,Arial,sans-serif;">Share</span>
</i></a>
</li>
<li>
<a href="#popupPrint" role="button" data-toggle="modal-popover" data-placement="top"><i
class="fa fa-print" aria-hidden="true"> <span style="font-family: Helvetica Neue",Helvetica,Arial,sans-serif;">Print</span>
</i></a>
</li>
<li>
@if(rndr.isValid()) {
<a href="@rndr.offlineLink()" target="_blank"><i class="fa fa-plug" aria-hidden="true"> <span
style="font-family: Helvetica Neue" ,Helvetica,Arial,sans-serif;">Offline</span></i></a>
} else {
<a title="Repo not found, print disabled."><i class="fa fa-plug" aria-hidden="true"> <span
style="font-family: Helvetica Neue" ,Helvetica,Arial,sans-serif;">Offline</span></i></a>
}
</li>
}
</ul>
<ul class="nav navbar-nav navbar-right">
<li>
@if(offline) {
<a>[ Offline ]</a>
} else {
<a><span style="color:gray">[ Fullscreen: Press F ]</span></a>
}
</li>
</ul>
</div> <!-- navbar -->
</div> <!-- container-fluid -->
</nav>

View File

@ -1,78 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer, offline: Boolean)
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@if(offline) {
<a class="navbar-brand" href="#">
} else {
<a class="navbar-brand" href="https://gitpitch.com">
}
<span style="letter-spacing: 0.1em;
color:#e49436;
font-size: 1.4em;
font-weight: bold;
text-transform:none">Git<span style="color:white">Pitch</span></span>
</a>
</div>
<div id="navbar" class="navbar-collapse collapse" style="margin-top: 3px">
<ul class="nav navbar-nav">
@if(offline) {
<li style="font-size:1.2em; color:white"><a href="#">@rndr.user()</a></li>
<li style="font-size:1.2em; color:white" class="hidden-sd hidden-xs"><p class="navbar-text" style="color:white">/</p></li>
<li style="font-size:1.2em; color:white"><a href="#">@rndr.repo()</a></li>
<li><a href="#" style="font-size:1.2em;color:gray" class="hidden-sd hidden-xs">{
@rndr.displayLangOrBranch() }</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="visible-lg visible-md" style="font-size:1.1em; color:white"><a href="#"><span
class="octicon octicon-star"></span> Star @rndr.stargazers()</a></li>
<li class="visible-lg visible-md" style="font-size:1.1em; color:white"><a href="#"><span
class="octicon octicon-repo-forked"></span> Fork @rndr.forks()</a></li>
@if(rndr.params().grs.equals("github")) {
<li style="font-size:1.2em; color:white"><a href="#"><span class="mega-octicon octicon-mark-github" style="font-size:1.3em"></span></a></li>
} else {
<li style="font-size:1.2em; color:white"><a href="#"><span class="fa fa-@rndr.params().grs" aria-hidden="true" style="font-size:1.4em"></span></a></li>
}
} else {
<li style="font-size:1.2em; color:white"><a href="@rndr.orgHub()">@rndr.user()</a></li>
<li style="font-size:1.2em; color:white" class="hidden-sd hidden-xs"><p class="navbar-text" style="color:white">/</p></li>
<li style="font-size:1.2em; color:white"><a href="@rndr.repoHub()">@rndr.repo()</a></li>
<li><a href="#" style="font-size:1.2em;color:gray" class="hidden-sd hidden-xs">{ @rndr.displayLangOrBranch() }</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="visible-lg visible-md" style="font-size:1.1em; color:white"><a href="@rndr.starHub()"><span
class="octicon octicon-star"></span> Star @rndr.stargazers()</a></li>
<li class="visible-lg visible-md" style="font-size:1.1em; color:white"><a href="@rndr.forkHub()"><span
class="octicon octicon-repo-forked"></span> Fork @rndr.forks()</a></li>
<li style="font-size:1.2em; color:white"><a href="@rndr.repoHub()">
@if(rndr.params().grs.equals("github")) {
<span class="mega-octicon octicon-mark-github" style="font-size:1.3em"></span>
}
@if(rndr.params().grs.equals("gitlab")) {
<span class="fa fa-gitlab" aria-hidden="true" style="font-size:1.4em"></span>
}
@if(rndr.params().grs.equals("bitbucket")) {
<span class="fa fa-bitbucket" aria-hidden="true" style="font-size:1.4em"></span>
}
@if(rndr.params().grs.equals("gitea") || rndr.params().grs.equals("gogs") ||
rndr.params.grs.equals("gitbucket")) {
<span class="fa fa-git-square" aria-hidden="true" style="font-size:1.4em"></span>
}
</a></li>
}
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>

View File

@ -1,30 +0,0 @@
@(deps: com.gitpitch.policies.Dependencies, offline: Boolean)
<script src="@deps.gitpitchjs(offline)/bootstrap-modal-popover-2.0.1.js"></script>
<script src="@deps.gitpitchjs(offline)/clipboard-1.5.12.js"></script>
<script type="text/javascript">
window.addEventListener('message',function(e) {
var key = e.message ? 'message' : 'data';
var data = e[key];
if(data == 'FIXEDTHEME') {
$( "#themes-popup-content" ).empty()
.append("<span style='padding: 10px 10px'><a target='_blank' href='https://github.com/gitpitch/gitpitch/wiki/Theme-Setting'>PITCHME.yaml</a> fixed theme in use.</span>");
}
},false);
</script>
<script type="text/javascript">
new Clipboard('.btn');
</script>
<script>
var a2a_config = a2a_config || {};
a2a_config.num_services = 5;
a2a_config.color_main = "D7E5ED";
a2a_config.color_border = "AECADB";
a2a_config.color_link_text = "333333";
a2a_config.color_link_text_hover = "333333";
a2a_config.prioritize = ["twitter", "linkedin", "facebook", "google_plus", "slashdot"];
</script>
<script async src="https://static.addtoany.com/menu/page.js"></script>

View File

@ -1,99 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer)
<div id="popupTheme" class="popover" style="text-align: center; font-size:1em">
<div class="arrow"></div>
<h5 class="popover-title">GitPitch Themes</h5>
<div id="themes-popup-content" class="popover-content themes">
@if(rndr.isValid()) {
<p style="width:215px; font-size:0.9em">Theme Switcher</p>
<hr style="margin-bottom: 10px; margin-top: 10px">
<a href='@rndr.pageLinkWithTheme("black")''>Black</a> -
<a href='@rndr.pageLinkWithTheme("moon")''>Moon</a> -
<a href='@rndr.pageLinkWithTheme("night")''>Night</a>
<hr style="margin-bottom: 10px; margin-top: 10px">
<a href='@rndr.pageLinkWithTheme("beige")''>Beige</a> -
<a href='@rndr.pageLinkWithTheme("sky")''>Sky</a> -
<a href='@rndr.pageLinkWithTheme("white")''>White</a>
<hr style="margin-bottom: 10px; margin-top: 10px">
<p style="width:215px; font-size:0.8em; color: gray">Tip: Use <b>PITCHME.yaml</b> to set a fixed theme for
your slideshow.</p>
} else {
Repo not found, themes disabled.
}
</div>
</div>
<div id="popupBadge" class="popover" style="text-align: center; font-size:1em">
<div class="arrow"></div>
<h5 class="popover-title">GitPitch Badge</h5>
<div class="popover-content">
@if(rndr.isValid()) {
<p style="width:215px; font-size:0.9em">Use the following markdown snippet to add a badge for this slideshow
to the README.md for your repo.</p>
<img src='@routes.Assets.versioned("badge.svg")'/>
<hr style="margin-bottom: 10px; margin-top: 10px">
<input id="badgeSnippet" value="@Html(rndr.pageBadge())"></input>
<button class="btn" data-clipboard-target="#badgeSnippet">
<i class="fa fa-clipboard" aria-hidden="true"></i>
</button>
} else {
Repo not found, badge disabled.
}
</div>
</div>
<div id="popupEmbed" class="popover" style="text-align: center; font-size:1em">
<div class="arrow"></div>
<h5 class="popover-title">GitPitch Embed</h5>
<div class="popover-content">
@if(rndr.isValid()) {
<p style="width:215px; font-size:0.9em">Use the following snippet to embed this GitPitch in your website or
blog.</p>
<hr style="margin-bottom: 10px; margin-top: 10px">
<input id="embedSnippet" value="@Html(rndr.pageEmbed())"></input>
<button class="btn" data-clipboard-target="#embedSnippet">
<i class="fa fa-clipboard" aria-hidden="true"></i>
</button>
} else {
Repo not found, embed disabled.
}
</div>
</div>
<div id="popupShare" class="popover" style="text-align: center; font-size:1em">
<div class="arrow"></div>
<h5 class="popover-title">GitPitch Share</h5>
<div class="popover-content">
@if(rndr.isValid()) {
<p style="width:215px">Help get the word out about this GitPitch by e-mail or social media.</p>
<hr style="margin-bottom: 10px; margin-top: 10px">
<input id="shareSnippet" value="@rndr.pageLink(true)"></input>
<button class="btn" data-clipboard-target="#shareSnippet">
<i class="fa fa-clipboard" aria-hidden="true"></i>
</button>
<hr style="margin-bottom: 10px; margin-top: 10px">
<div class="a2a_kit a2a_kit_size_32 a2a_default_style">
<a class="a2a_dd" href="https://www.addtoany.com/share"></a>
<a class="a2a_button_email"></a>
<a class="a2a_button_twitter"></a>
<a class="a2a_button_linkedin"></a>
<a class="a2a_button_facebook"></a>
<a class="a2a_button_google_plus"></a>
</div>
} else {
Repo not found, share disabled.
}
</div>
</div>
<div id="popupPrint" class="popover" style="text-align: center; font-size:1em">
<div class="arrow"></div>
<h5 class="popover-title">GitPitch Printing</h5>
<div class="popover-content">
@if(rndr.isValid()) {
<a href="@rndr.printLink()" target="_blank">Generate PDF on Server</a>
<hr style="margin-bottom: 10px; margin-top: 10px">
<a href="@rndr.printBrowserLink()" target="_blank">Generate PDF in Browser</a>
<hr style="margin-bottom: 10px; margin-top: 10px">
<p style="width:215px; font-size:0.8em; color: gray">Note: Browser support in <b>Chrome</b> only.
} else {
Repo not found, printing disabled.
}
</div>
</div>

View File

@ -1,36 +0,0 @@
@(deps: com.gitpitch.policies.Dependencies, offline: Boolean)
<style>
.navbar-brand {
padding: 17px;
}
.navbar-inverse .navbar-nav > li > a {
color: white;
}
.navbar-inverse .navbar-nav > li > a:hover {
color: #e49436;
}
.navbar-inverse .navbar-nav > li > a:visited {
color: white;
}
.themes > a {
color: #e49436;
}
.shortcut > a{
color: #e49436;
font-weight: bold;
}
#slideshow {
background-image: url('@deps.gitpitchimg(offline)/preloader-75.gif');
background-repeat: no-repeat;
background-position: center;
}
.centered {
display: flex;
justify-content: center;
align-items: center;
font-size:1.3em;
font-weight: bold;
}
</style>

View File

@ -1,18 +0,0 @@
<style>
.reveal .slides section .code-presenting-annotation {
font-size: 70%;
}
.reveal .slides section .fragment.current-only {
visibility: visible;
display: none;
}
.reveal .slides section .fragment.current-only.current-fragment {
display: block;
}
.line {
display: block;
}
.line.focus {
/* opacity: 1.0; */
}
</style>

View File

@ -1,11 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, offline: Boolean, serverPrinting: Boolean, gpToken: String)
@if(!offline) {
@if(!serverPrinting) {
@if(gpToken) {
@GoogleAnalytics(gpToken, false)
}
@if(ssm.hasGAToken()) {
@GoogleAnalytics(ssm.fetchGAToken(), true)
}
}
}

View File

@ -1,10 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, offline: Boolean)
@if(ssm.hasLogo()) {
<div id="gp-logo" style="@ssm.fetchLogoPosition()">
@if(offline) {
<img src="./assets/@ssm.fetchLogoName()"/>
} else {
<img src="@ssm.fetchLogo()"/>
}
</div>
}

View File

@ -1,142 +0,0 @@
@(offline: Boolean)
<style>
/* GitPitch Styling */
.centered {
display: flex;
justify-content: center;
align-items: center;
font-size:1.3em;
font-weight: bold;
}
.reveal .controls {
bottom: 20px;
}
/* GitPitch Menu Styling */
.gp-menu-bars {
font-size: 24px;
}
div.pitch-menu {
width: 100%;
text-align: center;
padding-top: 40px;
}
div.pitch-menu-logo {
height: 90px;
margin: 0 auto;
background-size: 280px 90px;
background-repeat: no-repeat;
@if(offline) {
background-image: url(assets/img/gp-logo-tagline.svg);
} else {
background-image: url(https://gitpitch.com/gp-logo-tagline.svg);
}
}
div.pitch-menu div.section-heading {
display: none;
color: white;
font-size: 1.1em;
letter-spacing: 2px;
text-transform: uppercase;
text-decoration: none;
}
div.pitch-menu .git-box {
width: 90%;
margin: 0 auto;
border: 1px solid gray;
border-radius: 5px;
}
div.git-box > table:first-of-type {
margin-left: 8%;
}
div.git-box, div.git-octicon, .git-octicon span {
font-family: 'Roboto', sans-serif;
font-size: 1em;
}
div.pitch-menu .git-box .short-link {
width: 8em;
font-size: 1em;
color: white;
overflow: hidden;
text-overflow: ellipsis;
font-family: 'Roboto', sans-serif;
}
div.pitch-menu .git-box a {
font-size: 1em;
text-decoration:none;
}
div.pitch-menu .git-box a a:hover {
color: #e48436;
}
div.pitch-menu .git-box table th, div.pitch-menu table td {
text-align: left;
padding: 0.6em 0.3em 0.6em 0.3em;
border: 0;
}
div.pitch-menu .git-label {
color: #b3b3b3;
font-size: 1em;
font-family: 'Roboto', sans-serif;
}
div.pitch-menu .git-octicon {
font: normal normal normal 16px/1 octicons;
font-size:1.1em;
color: white;
}
div.pitch-menu .git-octicon .star-fork {
padding-left: 4px;
color: white;
}
span.octicon.octicon-star, span.octicon.octicon-repo-forked {
color: #fff;
}
span.octicon span.star-fork {
font-family: 'Roboto', sans-serif;
font-size: 90%;
}
.git-octicon span.octicon {
font-family: octicons;
/* font-weight: bold !important; */
}
div.pitch-menu ul {
list-style-type: none;
margin: 14px 0 0px 0;
}
div.pitch-menu ul li.slideshow {
font-size: 0.95em;
cursor: pointer;
text-align: left;
padding: 10px 0;
}
div.pitch-menu ul li.home-git {
padding: 14px 0 14px 0;
font-size: 1.0em;
letter-spacing: 1.5px;
text-align: center;
}
div.pitch-menu ul li.home-git a {
font-family: 'Roboto', sans-serif !important;
}
div.pitch-menu ul li.home-themes {
padding: 14px 0 14px 0;
font-size: 1.0em;
text-transform: capitalize;
letter-spacing: 1.5px;
text-align: center;
border-top: solid 1px #222;
}
div.pitch-menu ul li.home-themes a {
font-family: 'Roboto', sans-serif !important;
}
hr.fade-away {
border: 0;
height: 1px;
background: #999;
background-image: linear-gradient(to right, #666, #999, #666);
width: 80%;
}
div.pitch-menu ul i.fa.fa-download, div.pitch-menu ul i.fa.fa-print, div.pitch-menu ul i.fa.fa-external-link {
padding-right: 5px;
}
</style>

View File

@ -1,40 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel)
<style>
#title-footer.footer-visible {
display: inline;
}
#title-footer.footer-hidden {
display: none;
}
#title-footer #notification {
font-family: 'Roboto', sans-serif;
}
#title-footer p {
text-align: center;
font-size: 0.9em;
line-height: 1;
margin: 0;
padding-top: 2px;
font-family: 'Roboto', sans-serif;
letter-spacing: 0;
}
#title-footer p.footer-hard {
@if(ssm.isDarkTheme()) {
color: #bbb;
} else {
color: #4d4d4d;
}
}
#title-footer p.footer-fade {
@if(ssm.isDarkTheme()) {
color: #bbb;
opacity: 0.9;
} else {
color: #4d4d4d;
opacity: 0.9;
}
font-size: 1.5vh;
letter-spacing: 0;
padding-top: 3px;
}
</style>

View File

@ -1,47 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, serverPrinting: Boolean, webPrinting: Boolean)
@if(!(serverPrinting || webPrinting)) {
<script>
function pushNotification(msg, fade) {
var footer = document.getElementById('title-footer')
var notification = document.getElementById('notification')
if(window.innerWidth < 700) {
footer.className = "footer-hidden";
} else {
footer.className = "footer-visible";
if(fade) {
notification.className = "footer-fade";
notification.innerHTML = msg;
} else {
notification.className = "footer-hard";
notification.innerHTML = msg;
}
}
};
function pushHelpNotification() {
if(window.innerWidth < 700)
pushNotification("@Html(ssm.fetchHelp(true))");
else
pushNotification("@Html(ssm.fetchHelp(false))");
}
function pushFootnoteNotification() {
@if(ssm.hasFootnote() && ssm.fetchFootnote().length() != 0) {
pushNotification("@Html(ssm.fetchFootnote())", true);
} else {
pushNotification("[ GitPitch @Html(ssm.params().atPretty()) ]", true);
}
}
function pushCodePresentingStepNotification(step, frags) {
pushNotification("Code Presenting - Step " + step + " / " + frags, true);
}
</script>
} else {
<script>
function pushNotification(msg, fade) {};
function pushHelpNotification() {}
function pushFootnoteNotification() {}
function pushCodePresentingStepNotification(step, frags) {}
</script>
}

View File

@ -1,3 +0,0 @@
@(rndr: com.gitpitch.utils.GitRepoRenderer)
<link rel="alternate" type="application/json+oembed" href='@rndr.oembed(rndr.slideshowAbs(), "json")' title="GitPitch - Markdown Presentations for Everyone on Git" />
<link rel="alternate" type="text/xml+oembed" href='@rndr.oembed(rndr.slideshowAbs(), "xml")' title="GitPitch - Markdown Presentations for Everyone on Git" />

View File

@ -1,4 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, serverPrinting: Boolean, webPrinting: Boolean)
@if(!(serverPrinting || webPrinting)) {
<footer id="title-footer"><p id="notification"></p></footer>
}

View File

@ -1,27 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, serverPrinting: Boolean, webPrinting: Boolean)
@if(serverPrinting || webPrinting) {
<div style="position: fixed; bottom: 10px; left: 20px; z-index: 999">
@if(ssm.hasFootnote()) {
<span style="color:@ssm.fetchThemeFontColorInverse(); font-size:0.8em; font-family: @ssm.fetchThemeFont();">@Html(ssm.fetchFootnote())</span>
} else {
@if(ssm.params().grs.equals("github")) {
<span class="octicon octicon-mark-github"
style="font-size:0.9em; color: @ssm.fetchThemeFontColorInverse()"></span>
}
@if(ssm.params().grs.equals("gitlab")) {
<i class="fa fa-gitlab" aria-hidden="true"
style="font-size:0.9em; color: @ssm.fetchThemeFontColorInverse()"></i>
}
@if(ssm.params().grs.equals("bitbucket")) {
<i class="fa fa-bitbucket" aria-hidden="true"
style="font-size:0.9em; color: @ssm.fetchThemeFontColorInverse()"></i>
}
@if(ssm.params().grs.equals("gitea") || ssm.params().grs.equals("gogs") ||
ssm.params().grs.equals("gitbucket")) {
<i class="fa fa-git-square" aria-hidden="true"
style="font-size:0.9em; color: @ssm.fetchThemeFontColorInverse()"></i>
}
<span style="color:@ssm.fetchThemeFontColorInverse(); font-size:0.8em; font-family: @ssm.fetchThemeFont();">@ssm.params().asLogo()</span>
}
</div>
}

View File

@ -1,205 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, deps: com.gitpitch.policies.Dependencies, offline:Boolean, serverPrinting: Boolean, webPrinting: Boolean)
<script>
Reveal.initialize({
@if(!(serverPrinting || webPrinting)) {
controls: true,
} else {
controls: false,
}
controlsLayout: '@ssm.fetchControlsLayout()',
progress: true,
embedded: true,
margin: 0.0,
showNotes: @ssm.showNotes(),
transition: '@ssm.fetchTransition()',
backgroundTransition: '@ssm.fetchTransition()',
autoSlide: @ssm.fetchAutoSlide(false),
loop: @ssm.fetchLoop(),
center: @ssm.fetchVerticalCenter(),
rtl: @ssm.fetchRTL(),
shuffle: @ssm.fetchShuffle(),
mouseWheel: @ssm.fetchMouseWheel(),
@if(!(serverPrinting || webPrinting)) {
slideNumber: 'c/t', // slideNumber: @ssm.fetchSlideNumber(),
} else {
slideNumber: false,
}
history: @ssm.fetchHistory(),
@if(ssm.mathEnabled()) {
math: {
@if(offline) {
mathjax: '@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/math/MathJax.js',
} else {
mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js',
}
config: '@ssm.fetchMathConfig()'
},
}
@if(!(serverPrinting || webPrinting ||
ssm.fetchAutoSlide(false) > 0)) {
menu: {
custom: [
@if(offline) {
{ title: 'Home', active: true,
icon: '<i class="fa fa-bookmark">',
src: 'menu.html' }
} else {
{ title: 'Home', active: true,
icon: '<i class="fa fa-bookmark">',
src: '@ssm.homePanel()' },
@if(!ssm.published()) {
{ title: 'Themes',
icon: '<i class="fa fa-code-fork">',
src: '@ssm.gitPanel()' },
{ title: 'GRS',
icon: '<i class="fa fa-image">',
src: '@ssm.themesPanel()' }
}
}
],
path : "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/menu",
themes : false,
transitions: false,
markers: true,
sticky: true,
autoOpen: true
},
}
dependencies: [
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/markdown/marked.js",
condition: function() {
return !!document.querySelector( '[data-markdown]' );
}},
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/markdown/markdown.js",
condition: function() {
return !!document.querySelector( '[data-markdown]' );
}},
@if(!(serverPrinting || webPrinting)) {
{ src:"@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/menu/menu-mod.js",
async: true},
}
@if(ssm.chartsEnabled()) {
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/chart/Chart.min.js"},
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/chart/csv2chart.js"},
}
@if(deps.cdnDisabled() || offline) {
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/notes/notes.js",
async: true },
}
@if(deps.highlightPluginEnabled()) {
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/highlight/highlight.js",
async: true, callback: function() {
hljs.initHighlightingOnLoad();
} },
} else {
{ src: '@deps.highlightjs(offline)/highlight.js', async: true },
{ src: '@deps.highlightjs(offline)/reveal-code-focus-1.0.0-mod.js',
async: true,
callback: function() {
RevealCodeFocus();
}
},
}
@if(ssm.mathEnabled()) {
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/math/math.js",
async: true }
}
]
});
Reveal.addEventListener('ready', function(evt) {
upgradeAnchors();
if (evt.indexh === 0 && evt.indexv === 0) {
pushHelpNotification();
} else {
pushFootnoteNotification();
}
});
Reveal.addEventListener('menu-ready', function(evt) {
manageMenuPolicy();
});
Reveal.addEventListener('slidechanged', function(evt) {
if (evt.indexh === 0 && evt.indexv === 0) {
pushHelpNotification();
} else {
pushFootnoteNotification();
}
});
Reveal.configure({
keyboard: {
88: function() { // bind "x" key to "select" code block content
var currentSlide = Reveal.getCurrentSlide();
var preBlock = $(currentSlide).find("pre");
if(preBlock.length > 0) {
if (window.getSelection) {
var range = document.createRange();
range.selectNodeContents(preBlock[0]);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
}
}
});
function enterFullscreen() {
Reveal.triggerKey(70);
};
function enterOverview() {
Reveal.toggleOverview();
};
function enterBlackout() {
Reveal.togglePause();
};
function enterHelp() {
Reveal.toggleHelp();
}
function enableEvents() {
Reveal.addEventListeners();
};
function disableEvents() {
Reveal.removeEventListeners();
};
function manageMenuPolicy() {
if(RevealMenu && RevealMenu.isOpen()) {
RevealMenu.toggle();
}
}
function upgradeAnchors() {
Array.from(document.getElementsByTagName('a')).forEach($link => {
if ($link.hostname !== window.location.hostname) {
$link.setAttribute('rel', 'noopener noreferrer');
$link.setAttribute('target', '_blank');
}
});
}
</script>
@if(ssm.remoteControlEnabled()) {
<script>
Reveal.configure({
keyboard: {
@ssm.remoteControlPrevKey(): 'prev',
@ssm.remoteControlNextKey(): 'next'
}
});
</script>
}

View File

@ -1,50 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel)
<style>
.centered {
display: flex;
justify-content: center;
align-items: center;
font-size:1.3em;
font-weight: bold;
}
#gp-logo img {
max-height: 3.5em;
max-width: none;
}
@if(ssm.options() != null &&
ssm.options().fetchRevealVersion(ssm.params()) == "3.5.0") {
.reveal .speaker-notes {
background-color: black;
opacity : 0.8;
}
}
.reveal .controls {
bottom: 20px;
}
.reveal .slide-number {
bottom: 3px !important;
font-size: 11px !important;
color: gray !important;
background-color: inherit !important;
}
@if(ssm.options() != null &&
ssm.options().isLeftLayout(ssm.params())) {
.reveal .slides {
text-align: left;
}
.reveal .slides section>* {
margin-left: 0;
margin-right: 0;
}
}
@if(ssm.options() != null &&
ssm.options().isRightLayout(ssm.params())) {
.reveal .slides {
text-align: right;
}
.reveal .slides section>* {
margin-left: 0;
margin-right: 0;
}
}
</style>

View File

@ -1,15 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel, deps: com.gitpitch.policies.Dependencies, offline: Boolean, webPrinting: Boolean)
<link href="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/css/reveal.css" rel="stylesheet" type="text/css"/>
<link href="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/css/theme/@ssm.fetchThemeCSS()" rel="stylesheet" type="text/css" id="theme"/>
<link href="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/title-footer/title-footer-mod.css" rel="stylesheet" type="text/css" id="theme"/>
@if(webPrinting) {
<link href="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/css/print/pdf.css" rel="stylesheet" type="text/css"/>
} else {
<link href="@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/css/print/paper.css" rel="stylesheet" type="text/css"/>
}
<link href="@deps.highlightjs(offline)/@ssm.fetchHighlightCSS()" rel="stylesheet" type="text/css"/>
<link href="@deps.octicons(offline)/octicons.css" rel="stylesheet" type="text/css"/>
<link href="@deps.fontawesome(offline)/css/font-awesome.min.css" rel="stylesheet" type="text/css"/>
@if(!offline) {
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
}

View File

@ -1,6 +0,0 @@
@(ssm: com.gitpitch.models.SlideshowModel)
@if(ssm.hasThemeOverride()) {
<style>
@Html(ssm.fetchThemeOverride())
</style>
}

View File

@ -1,21 +0,0 @@
name := """server"""
version := "2.0"
organization := "com.gitpitch"
lazy val root = (project in file(".")).enablePlugins(PlayJava, LauncherJarPlugin)
scalaVersion := "2.11.11"
libraryDependencies ++= Seq(
cache,
javaWs,
filters
)
libraryDependencies ++= Seq(
"com.typesafe.netty" % "netty-reactive-streams-http" % "1.0.6",
"com.google.guava" % "guava" % "19.0",
"com.google.inject.extensions" % "guice-assistedinject" % "4.0",
"org.yaml" % "snakeyaml" % "1.17",
"commons-io" % "commons-io" % "2.5"
)

View File

@ -1,510 +0,0 @@
# This is the main configuration file for the application.
# https://www.playframework.com/documentation/latest/ConfigFile
# ~~~~~
# Play uses HOCON as its configuration file format. HOCON has a number
# of advantages over other config formats, but there are two things that
# can be used when modifying settings.
#
# You can include other configuration files in this main application.conf file:
#include "extra-config.conf"
#
# You can declare variables and substitute for them:
#mykey = ${some.value}
#
# And if an environment variable exists when there is no other subsitution, then
# HOCON will fall back to substituting environment variable:
#mykey = ${JAVA_HOME}
## Akka
# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration
# https://www.playframework.com/documentation/latest/JavaAkka#Configuration
# ~~~~~
# Play uses Akka internally and exposes Akka Streams and actors in Websockets and
# other streaming HTTP responses.
akka {
# "akka.log-config-on-start" is extraordinarly useful because it log the complete
# configuration at INFO level, including defaults and overrides, so it s worth
# putting at the very top.
#
# Put the following in your conf/logback.xml file:
#
# <logger name="akka.actor" level="INFO" />
#
# And then uncomment this line to debug the configuration.
#
#log-config-on-start = true
}
## Secret key
# http://www.playframework.com/documentation/latest/ApplicationSecret
# ~~~~~
# The secret key is used to sign Play's session cookie.
# This must be changed for production, but we don't recommend you change it in this file.
play.crypto.secret = "changeme"
play.crypto.secret = ${?PLAY_CRYPTO_SECRET}
## Modules
# https://www.playframework.com/documentation/latest/Modules
# ~~~~~
# Control which modules are loaded when Play starts. Note that modules are
# the replacement for "GlobalSettings", which are deprecated in 2.5.x.
# Please see https://www.playframework.com/documentation/latest/GlobalSettings
# for more information.
#
# You can also extend Play functionality by using one of the publically available
# Play modules: https://playframework.com/documentation/latest/ModuleDirectory
play.modules {
# By default, Play will load any class called Module that is defined
# in the root package (the "app" directory), or you can define them
# explicitly below.
# If there are any built-in modules that you want to disable, you can list them here.
#enabled += my.application.Module
# If there are any built-in modules that you want to disable, you can list them here.
#disabled += ""
}
## IDE
# https://www.playframework.com/documentation/latest/IDE
# ~~~~~
# Depending on your IDE, you can add a hyperlink for errors that will jump you
# directly to the code location in the IDE in dev mode. The following line makes
# use of the IntelliJ IDEA REST interface:
#play.editor=http://localhost:63342/api/file/?file=%s&line=%s
## Internationalisation
# https://www.playframework.com/documentation/latest/JavaI18N
# https://www.playframework.com/documentation/latest/ScalaI18N
# ~~~~~
# Play comes with its own i18n settings, which allow the user's preferred language
# to map through to internal messages, or allow the language to be stored in a cookie.
play.i18n {
# The application languages
langs = ["en"]
# Whether the language cookie should be secure or not
#langCookieSecure = true
# Whether the HTTP only attribute of the cookie should be set to true
#langCookieHttpOnly = true
}
## Play HTTP settings
# ~~~~~
play.http {
## Router
# https://www.playframework.com/documentation/latest/JavaRouting
# https://www.playframework.com/documentation/latest/ScalaRouting
# ~~~~~
# Define the Router object to use for this application.
# This router will be looked up first when the application is starting up,
# so make sure this is the entry point.
# Furthermore, it's assumed your route file is named properly.
# So for an application router like `my.application.Router`,
# you may need to define a router file `conf/my.application.routes`.
# Default to Routes in the root package (aka "apps" folder) (and conf/routes)
#router = my.application.Router
## Action Creator
# https://www.playframework.com/documentation/latest/JavaActionCreator
# ~~~~~
#actionCreator = null
## ErrorHandler
# https://www.playframework.com/documentation/latest/JavaRouting
# https://www.playframework.com/documentation/latest/ScalaRouting
# ~~~~~
# If null, will attempt to load a class called ErrorHandler in the root package,
#errorHandler = null
## Filters
# https://www.playframework.com/documentation/latest/ScalaHttpFilters
# https://www.playframework.com/documentation/latest/JavaHttpFilters
# ~~~~~
# Filters run code on every request. They can be used to perform
# common logic for all your actions, e.g. adding common headers.
# Defaults to "Filters" in the root package (aka "apps" folder)
# Alternatively you can explicitly register a class here.
#filters = my.application.Filters
filters = "com.gitpitch.filters.PitchFilters"
## Session & Flash
# https://www.playframework.com/documentation/latest/JavaSessionFlash
# https://www.playframework.com/documentation/latest/ScalaSessionFlash
# ~~~~~
session {
# Sets the cookie to be sent only over HTTPS.
#secure = true
# Sets the cookie to be accessed only by the server.
#httpOnly = true
# Sets the max-age field of the cookie to 5 minutes.
# NOTE: this only sets when the browser will discard the cookie. Play will consider any
# cookie value with a valid signature to be a valid session forever. To implement a server side session timeout,
# you need to put a timestamp in the session and check it at regular intervals to possibly expire it.
#maxAge = 300
# Sets the domain on the session cookie.
#domain = "example.com"
}
flash {
# Sets the cookie to be sent only over HTTPS.
#secure = true
# Sets the cookie to be accessed only by the server.
#httpOnly = true
}
}
## Netty Provider
# https://www.playframework.com/documentation/latest/SettingsNetty
# ~~~~~
play.server.netty {
# Whether the Netty wire should be logged
#log.wire = true
# If you run Play on Linux, you can use Netty's native socket transport
# for higher performance with less garbage.
#transport = "native"
}
## WS (HTTP Client)
# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS
# ~~~~~
# The HTTP client primarily used for REST APIs. The default client can be
# configured directly, but you can also create different client instances
# with customized settings. You must enable this by adding to build.sbt:
#
# libraryDependencies += ws // or javaWs if using java
#
play.ws {
# Sets HTTP requests not to follow 302 requests
#followRedirects = false
# Sets the maximum number of open HTTP connections for the client.
#ahc.maxConnectionsTotal = 50
## WS SSL
# https://www.playframework.com/documentation/latest/WsSSL
# ~~~~~
ssl {
# Configuring HTTPS with Play WS does not require programming. You can
# set up both trustManager and keyManager for mutual authentication, and
# turn on JSSE debugging in development with a reload.
#debug.handshake = true
#trustManager = {
# stores = [
# { type = "JKS", path = "exampletrust.jks" }
# ]
#}
}
}
## Cache
# https://www.playframework.com/documentation/latest/JavaCache
# https://www.playframework.com/documentation/latest/ScalaCache
# ~~~~~
# Play comes with an integrated cache API that can reduce the operational
# overhead of repeated requests. You must enable this by adding to build.sbt:
#
# libraryDependencies += cache
#
play.cache {
# If you want to bind several caches, you can bind the individually
#bindCaches = ["db-cache", "user-cache", "session-cache"]
}
## Filters
# https://www.playframework.com/documentation/latest/Filters
# ~~~~~
# There are a number of built-in filters that can be enabled and configured
# to give Play greater security. You must enable this by adding to build.sbt:
#
# libraryDependencies += filters
#
play.filters {
## CORS filter configuration
# https://www.playframework.com/documentation/latest/CorsFilter
# ~~~~~
# CORS is a protocol that allows web applications to make requests from the browser
# across different domains.
# NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has
# dependencies on CORS settings.
cors {
# Filter paths by a whitelist of path prefixes
#pathPrefixes = ["/some/path", ...]
# The allowed origins. If null, all origins are allowed.
#allowedOrigins = ["http://www.example.com"]
allowedOrigins = [".gitpitch.com", "localhost:9000", "127.0.0.1:9000"]
# The allowed HTTP methods. If null, all methods are allowed
#allowedHttpMethods = ["GET", "POST"]
}
## CSRF Filter
# https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter
# https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter
# ~~~~~
# Play supports multiple methods for verifying that a request is not a CSRF request.
# The primary mechanism is a CSRF token. This token gets placed either in the query string
# or body of every form submitted, and also gets placed in the users session.
# Play then verifies that both tokens are present and match.
csrf {
# Sets the cookie to be sent only over HTTPS
#cookie.secure = true
# Defaults to CSRFErrorHandler in the root package.
#errorHandler = MyCSRFErrorHandler
}
## Security headers filter configuration
# https://www.playframework.com/documentation/latest/SecurityHeaders
# ~~~~~
# Defines security headers that prevent XSS attacks.
# If enabled, then all options are set to the below configuration by default:
headers {
# The X-Frame-Options header. If null, the header is not set.
#frameOptions = "DENY"
frameOptions = null
# The X-XSS-Protection header. If null, the header is not set.
#xssProtection = "1; mode=block"
# The X-Content-Type-Options header. If null, the header is not set.
#contentTypeOptions = "nosniff"
# The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
#permittedCrossDomainPolicies = "master-only"
# The Content-Security-Policy header. If null, the header is not set.
#contentSecurityPolicy = "default-src 'self'"
contentSecurityPolicy = null
}
## Allowed hosts filter configuration
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
# ~~~~~
# Play provides a filter that lets you configure which hosts can access your application.
# This is useful to prevent cache poisoning attacks.
hosts {
# Allow requests to example.com, its subdomains, and localhost:9000.
allowed = ["localhost", "127.0.0.1", ".local"]
}
}
## Evolutions
# https://www.playframework.com/documentation/latest/Evolutions
# ~~~~~
# Evolutions allows database scripts to be automatically run on startup in dev mode
# for database migrations. You must enable this by adding to build.sbt:
#
# libraryDependencies += evolutions
#
play.evolutions {
# You can disable evolutions for a specific datasource if necessary
#db.default.enabled = false
}
## Database Connection Pool
# https://www.playframework.com/documentation/latest/SettingsJDBC
# ~~~~~
# Play doesn't require a JDBC database to run, but you can easily enable one.
#
# libraryDependencies += jdbc
#
play.db {
# The combination of these two settings results in "db.default" as the
# default JDBC pool:
#config = "db"
#default = "default"
# Play uses HikariCP as the default connection pool. You can override
# settings by changing the prototype:
prototype {
# Sets a fixed JDBC connection pool size of 50
#hikaricp.minimumIdle = 50
#hikaricp.maximumPoolSize = 50
}
}
## JDBC Datasource
# https://www.playframework.com/documentation/latest/JavaDatabase
# https://www.playframework.com/documentation/latest/ScalaDatabase
# ~~~~~
# Once JDBC datasource is set up, you can work with several different
# database options:
#
# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick
# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA
# EBean: https://playframework.com/documentation/latest/JavaEbean
# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm
#
db {
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
# https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
#default.driver = org.h2.Driver
#default.url = "jdbc:h2:mem:play"
#default.username = sa
#default.password = ""
# You can turn on SQL logging for any datasource
# https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
#default.logSql=true
}
# GitPitch Custom Configuration
gitpitch {
hostname = "localhost:9000"
https = false
storage {
#
# Directory indicated for this property must exist on disk.
# When setting a custom path for this directory you must
# specify an absolute path.
#
home = "/tmp/gitpitch/swap"
}
decktape {
#
# Absolute path to decktape executable.
#
home = "/usr/local/bin/decktape"
#
# Optional args passed to decktape executable.
# For example, to workaround Decktape #103 related to
# Puppeteer Issue #290, uncomment and use the following:
# args = "--no-sandbox"
}
offline {
prod {
fixed {
assets {
home = "./lib/com.gitpitch.server-2.0-assets.jar"
}
}
}
dev {
fixed {
assets {
home = "./public/libs"
}
}
math {
assets {
home = "./public/libs-math"
}
}
}
}
dependency {
revealjs = "3.7.0"
bootstrap = "3.3.6"
jquery = "2.2.4"
fontawesome = "4.7.0"
octicons = "3.5.0"
highlightjs = "9.13.1"
highlight {
plugin = false
}
}
git {
repo {
services = [
{
name = "GitHub"
type = "github"
site = "https://github.com/"
apibase = "https://api.github.com/"
// apitoken = "token your-github-access-token-here"
apitokenheader = "Authorization"
rawbase = "https://raw.githubusercontent.com/"
gistbase = "https://gist.githubusercontent.com/"
branchdelim = "~"
default = "true"
}
{
name = "GitLab"
type = "gitlab"
site = "https://gitlab.com/"
apibase = "https://gitlab.com/api/v4/"
// apitoken = "your-gitlab-access-token-here"
apitokenheader = "PRIVATE-TOKEN"
rawbase = "https://gitlab.com/"
branchdelim = "~"
default = "false"
}
{
name = "Bitbucket"
type = "bitbucket"
site = "https://bitbucket.org/"
apibase = "https://api.bitbucket.org/2.0/"
// apitoken = "your-bitbucket-access-token-here"
apitokenheader = "Authorization"
rawbase = "https://bitbucket.org/"
branchdelim = "~"
default = "false"
}
{
name = "Gitea"
type = "gitea"
site = "https://localhost:3000/"
apibase = "http://localhost:3000/api/v1/"
// apitoken = "token your-gitea-app-token-here"
apitokenheader = "Authorization"
rawbase = "http://localhost:3000/"
branchdelim = "~"
default = "false"
}
{
name = "Gogs"
type = "gogs"
site = "https://localhost:3000/"
apibase = "http://localhost:3000/api/v1/"
apitoken = "token your-gitea-app-token-here"
apitokenheader = "Authorization"
rawbase = "http://localhost:3000/"
branchdelim = "~"
default = "false"
}
{
name = "GitBucket"
type = "gitbucket"
site = "http://localhost:8080/"
apibase = "http://localhost:8080/api/v3/"
// apitoken = "token your-gitbucket-access-token-here"
apitokenheader = "Authorization"
rawbase = "http://localhost:8080/"
branchdelim = "~"
default = "false"
}
]
}
}
revealjs {
themes = ["black", "moon", "night", "beige", "sky", "white"]
}
google {
analytics {
// token = "your-google-analytics-token"
}
}
}

View File

@ -1,58 +0,0 @@
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
<configuration>
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${application.home:-.}/logs/server.log</file>
<encoder>
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date %thread %coloredLevel %logger{15} - %message%n%xException{10}</pattern>
</encoder>
</appender>
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
</appender>
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="STDOUT"/>
</appender>
<logger name="play" level="INFO"/>
<logger name="com.gitpitch.controllers" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<logger name="com.gitpitch.services" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<logger name="com.gitpitch.models" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<logger name="com.gitpitch.filters" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<logger name="com.gitpitch.git" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<logger name="com.gitpitch.utils" level="DEBUG" additivity="false">
<appender-ref ref="ASYNCSTDOUT"/>
</logger>
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF"/>
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF"/>
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF"/>
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF"/>
<root level="WARN">
<appender-ref ref="ASYNCFILE"/>
<appender-ref ref="ASYNCSTDOUT"/>
</root>
</configuration>

View File

@ -1,48 +0,0 @@
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
# Serve GitPitch markdown template bundles as zip archives.
GET /template/download/:template com.gitpitch.controllers.PitchController.template(template:String)
# Serve GitPitch oEmbed provider responses.
GET /pitchme/oembed com.gitpitch.controllers.PitchController.oembed(url:String, format:String ?= null, width:String ?= null, height:String ?= null, maxwidth:String ?= null, maxheight:String ?= null, referrer:String ?= null)
# Serve GitPitch GIST iFrame for {gid}.
GET /pitchme/gist/:gid com.gitpitch.controllers.PitchController.gist(gid:String)
# Serve GitPitch Home Side Panel
GET /pitchme/home/:grs/:user/:repo/:b/:t com.gitpitch.controllers.PitchController.home(grs:String, user:String, repo:String, b:String, t:String, p:String ?= null, offline:String ?= null)
# Serve GitPitch Git (GRS) Side Panel
GET /pitchme/git/:grs/:user/:repo/:b/:t com.gitpitch.controllers.PitchController.git(grs:String, user:String, repo:String, b:String, t:String, p:String ?= null, offline:String ?= null)
# Serve GitPitch Themes Side Panel
GET /pitchme/themes/:grs/:user/:repo/:b/:t com.gitpitch.controllers.PitchController.themes(grs:String, user:String, repo:String, b:String, t:String, p:String ?= null, offline:String ?= null)
# Serve PITCHME.pdf.
GET /pitchme/print/:grs/:user/:repo/:b/:t/PITCHME.pdf com.gitpitch.controllers.PitchController.print(grs:String, user:String, repo:String, b:String, t:String, p:String ?= null, n:String ?= null)
# Serve PITCHME.zip.
GET /pitchme/offline/:grs/:user/:repo/:b/:t/PITCHME.zip com.gitpitch.controllers.PitchController.offline(grs:String, user:String, repo:String, b:String, t:String, p:String ?= null, n:String ?= null)
# Redirect to GitHub OAuth Access Request
# GET /pitchme/authreq com.gitpitch.controllers.AuthController.authreq()
# Handle GitHub OAuth Callback
# GET /pitchme/authorized com.gitpitch.controllers.AuthController.authorized(code:String ?= null, state:String ?= null)
# Serve PITCHME.md markdown.
GET /pitchme/markdown/:grs/:user/:repo/:b/PITCHME.md com.gitpitch.controllers.PitchController.markdown(grs:String, user:String, repo:String, b:String, p:String ?= null)
# Serve PITCHME.md presentation page.
GET /:user/:repo/:b com.gitpitch.controllers.PitchController.slideshow(user:String, repo:String, b:String, grs:String ?= null, t:String ?= null, p:String?= null, n:String ?= null, offline:String ?= null, fragments:String ?= null, `print-pdf`:String ?= null)
# Serve PITCHME.md presentation page, short URI format.
GET /:user/:repo com.gitpitch.controllers.PitchController.slideshow(user:String, repo:String, b:String ?= null, grs:String ?= null, t:String ?= null, p:String?= null, n:String ?= null, offline:String ?= null, fragments:String ?= null, `print-pdf`:String ?= null)
# Catch-all route redirect to website.
GET /*path com.gitpitch.controllers.PitchController.catchall(path:String)

5
deps/package.json vendored
View File

@ -1,5 +0,0 @@
{
"dependencies": {
"decktape": "^2.6.1"
}
}

0
docs/.nojekyll Normal file
View File

4
docs/README.md Normal file
View File

@ -0,0 +1,4 @@
# GitPitch 4.0
!> Slide Decks for Tech Conferences, Training, Developer Advocates, and Educators.

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Some files were not shown because too many files have changed in this diff Show More