Skip to content
This repository has been archived by the owner on Jun 21, 2022. It is now read-only.

Commit

Permalink
Merge pull request #18 from olenagerasimova/16
Browse files Browse the repository at this point in the history
#16 - transfer dashboard
  • Loading branch information
olegmoz authored Dec 8, 2020
2 parents ea241bf + 706073f commit 7f51542
Show file tree
Hide file tree
Showing 10 changed files with 605 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ SOFTWARE.
<groupId>com.jcabi</groupId>
<artifactId>jcabi-log</artifactId>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-matchers</artifactId>
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/artipie/management/dashboard/Page.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 artipie.com
*
* 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 NON-INFRINGEMENT. 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.artipie.management.dashboard;

import io.reactivex.Single;
import java.util.Map;

/**
* HTML page.
* @since 0.2
*/
interface Page {

/**
* Render page to HTML string.
* @param line Request line
* @param headers Request headers
* @return HTML string
*/
Single<String> render(String line, Iterable<Map.Entry<String, String>> headers);
}
67 changes: 67 additions & 0 deletions src/main/java/com/artipie/management/dashboard/PageSlice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 artipie.com
*
* 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 NON-INFRINGEMENT. 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.artipie.management.dashboard;

import com.artipie.http.Headers;
import com.artipie.http.Response;
import com.artipie.http.Slice;
import com.artipie.http.async.AsyncResponse;
import com.artipie.http.rs.RsWithBody;
import com.artipie.http.rs.RsWithHeaders;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.reactivestreams.Publisher;

/**
* Slice to render HTML pages.
* @since 0.2
*/
final class PageSlice implements Slice {

/**
* HTML page.
*/
private final Page page;

/**
* New slice for page.
* @param page Page
*/
PageSlice(final Page page) {
this.page = page;
}

@Override
public Response response(final String line, final Iterable<Map.Entry<String, String>> headers,
final Publisher<ByteBuffer> body) {
return new RsWithHeaders(
new AsyncResponse(
this.page.render(line, headers)
.map(html -> new RsWithBody(html, StandardCharsets.UTF_8))
),
new Headers.From("Content-Type", "text/html")
);
}
}
144 changes: 144 additions & 0 deletions src/main/java/com/artipie/management/dashboard/RepoPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 artipie.com
*
* 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 NON-INFRINGEMENT. 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.artipie.management.dashboard;

import com.amihaiemil.eoyaml.Scalar;
import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;
import com.amihaiemil.eoyaml.YamlMappingBuilder;
import com.artipie.asto.Key;
import com.artipie.asto.Storage;
import com.artipie.asto.rx.RxStorageWrapper;
import com.artipie.http.rq.RequestLineFrom;
import com.artipie.management.api.ContentAsYaml;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.helper.ConditionalHelpers;
import com.github.jknack.handlebars.io.TemplateLoader;
import io.reactivex.Single;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.cactoos.map.MapEntry;
import org.cactoos.map.MapOf;

/**
* Repository page.
* @since 0.2
*/
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
final class RepoPage implements Page {

/**
* URI path pattern.
*/
private static final Pattern PTN = Pattern.compile("/dashboard/(?<key>[^/.]+/[^/.]+)/?");

/**
* Template engine.
*/
private final Handlebars handlebars;

/**
* Settings storage.
*/
private final Storage storage;

/**
* New page.
* @param tpl Template engine
* @param storage Settings storage
*/
RepoPage(final TemplateLoader tpl, final Storage storage) {
this.handlebars = new Handlebars(tpl);
this.storage = storage;
}

@Override
public Single<String> render(final String line,
final Iterable<Map.Entry<String, String>> headers) {
final Matcher matcher = PTN.matcher(new RequestLineFrom(line).uri().getPath());
if (!matcher.matches()) {
throw new IllegalStateException("Should match");
}
final String name = matcher.group("key");
this.handlebars.registerHelper("eq", ConditionalHelpers.eq);
final String[] parts = name.split("/");
final Key.From key = new Key.From(String.format("%s.yaml", name));
// @checkstyle LineLengthCheck (30 lines)
final RxStorageWrapper rxsto = new RxStorageWrapper(this.storage);
return rxsto.exists(key).filter(exists -> exists).flatMapSingleElement(
ignore -> rxsto.value(key).to(new ContentAsYaml()).map(
config -> {
final YamlMapping repo = config.yamlMapping("repo");
YamlMappingBuilder builder = Yaml.createYamlMappingBuilder();
builder = builder.add("type", repo.value("type"));
if (repo.value("storage") != null
&& Scalar.class.isAssignableFrom(repo.value("storage").getClass())) {
builder = builder.add("storage", repo.value("storage"));
}
builder = builder.add("permissions", repo.value("permissions"));
if (repo.value("settings") != null) {
builder = builder.add("settings", repo.value("settings"));
}
return Yaml.createYamlMappingBuilder().add("repo", builder.build()).build();
}
).map(
yaml -> this.handlebars.compile("repo").apply(
new MapOf<>(
new MapEntry<>("title", name),
new MapEntry<>("user", parts[0]),
new MapEntry<>("name", parts[1]),
new MapEntry<>("config", yaml.toString()),
new MapEntry<>("found", true),
new MapEntry<>("type", yaml.yamlMapping("repo").value("type").asScalar().value())
)
)
)
).switchIfEmpty(
Single.fromCallable(
() -> this.handlebars.compile("repo").apply(
new MapOf<>(
new MapEntry<>("title", name),
new MapEntry<>("user", parts[0]),
new MapEntry<>("name", parts[1]),
new MapEntry<>("found", false),
new MapEntry<>(
"type",
URLEncodedUtils.parse(
new RequestLineFrom(line).uri(),
StandardCharsets.UTF_8
).stream()
.filter(pair -> "type".equals(pair.getName()))
.findFirst().map(NameValuePair::getValue)
.orElse("maven")
)
)
)
)
);
}
}
96 changes: 96 additions & 0 deletions src/main/java/com/artipie/management/dashboard/UserPage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 artipie.com
*
* 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 NON-INFRINGEMENT. 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.artipie.management.dashboard;

import com.artipie.asto.Key;
import com.artipie.asto.Storage;
import com.artipie.asto.rx.RxStorageWrapper;
import com.artipie.http.rq.RequestLineFrom;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.io.TemplateLoader;
import io.reactivex.Single;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.cactoos.map.MapEntry;
import org.cactoos.map.MapOf;

/**
* User page.
* @since 0.2
*/
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
final class UserPage implements Page {

/**
* URI path pattern.
*/
private static final Pattern PTN = Pattern.compile("/dashboard/(?<user>[^/.]+)/?");

/**
* Template engine.
*/
private final Handlebars handlebars;

/**
* Settings.
*/
private final Storage storage;

/**
* New page.
* @param tpl Template loader
* @param storage Settings storage
*/
UserPage(final TemplateLoader tpl, final Storage storage) {
this.handlebars = new Handlebars(tpl);
this.storage = storage;
}

@Override
public Single<String> render(final String line,
final Iterable<Map.Entry<String, String>> headers) {
final Matcher matcher = PTN.matcher(new RequestLineFrom(line).uri().getPath());
if (!matcher.matches()) {
throw new IllegalStateException("Should match");
}
final String user = matcher.group("user");
return new RxStorageWrapper(this.storage).list(new Key.From(user))
.map(
repos -> this.handlebars.compile("user").apply(
new MapOf<>(
new MapEntry<>("title", user),
new MapEntry<>("user", user),
new MapEntry<>(
"repos",
repos.stream()
.map(key -> key.string().replace(".yaml", ""))
.collect(Collectors.toList())
)
)
)
);
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/artipie/management/dashboard/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 artipie.com
*
* 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 NON-INFRINGEMENT. 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.
*/

/**
* Artipie dashboard.
*
* @since 0.2
*/
package com.artipie.management.dashboard;
Loading

3 comments on commit 7f51542

@0pdd
Copy link

@0pdd 0pdd commented on 7f51542 Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 569-26fa1589 discovered in src/main/java/com/artipie/management/Users.java and submitted as #20. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link

@0pdd 0pdd commented on 7f51542 Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 231-f3499255 discovered in src/test/java/com/artipie/management/api/CookiesTest.java and submitted as #21. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link

@0pdd 0pdd commented on 7f51542 Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 2-f08326a0 discovered in src/test/java/com/artipie/management/FakeRepoPerms.java and submitted as #22. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.