improvements to generating URIs and some template tweaks, minor tidying

This commit is contained in:
Yvan 2025-02-04 19:42:09 +00:00
parent 1682cbe81f
commit 516f90bf1f
6 changed files with 93 additions and 35 deletions

View file

@ -76,7 +76,15 @@ public class Bot {
Bot() {
}
Bot( String username, String name, String summary, Instant published, KeyPair keyPair, String type, boolean manuallyApproveFollowers, boolean indexable ) {
Bot(
String username,
String name,
String summary,
Instant published,
KeyPair keyPair,
String type,
boolean manuallyApproveFollowers,
boolean indexable ) {
this.username = username;
this.name = name;
this.summary = summary;
@ -86,5 +94,6 @@ public class Bot {
this.manuallyApproveFollowers = manuallyApproveFollowers;
this.indexable = indexable;
}
}

View file

@ -4,6 +4,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
/**
@ -35,36 +36,73 @@ public class BotService {
}
// whilst the URI structure of the below are up to the implementor we're using Mastodon as a reference
// whilst the URI structure of the below are up to the implementer we're using Mastodon as a reference
// TODO: perhaps these could just be templated elsewhere... or part of a separat JSON generator
// TODO: I've fiddled around loads with where to house/generate the values
// from the calls below, they have ended up here mainly as this is where it
// is cleanest to access the configuration properties.
//
// Opinion in material I've read seems very firm that knowledge of
// "configuration" should not exist at Entity level so I have not made them
// members of the Bot class. I've toyed with the idea of them simply all
// being kept as database values and generated on creation... and in some
// ways that is simply cleaner and thus still has an appeal to it. I just
// also feel uncomfortable about having a load of "derived data" in the
// database, even though there is also a efficiency argument. Perhaps the
// combination of both efficiency + design-readability should win it. (In
// which case this code could well just stay here to be used at creation.)
/**
* Generate the users URI
* Generate the webfinger subject
*/
private String getUsersURI() {
return props.getScheme() + "://" + props.getDomain() + "/users/";
public String getWebfingerSubject(Bot bot) {
return "acct:" + bot.getUsername() + "@" + props.getDomain();
}
/**
* The"id" of a bot (user/actor) is a URI combining domain and username: https://<domain>/users/<username>
* Generate the webfinger subject
*/
public String getHandle(Bot bot) {
return "@" + bot.getUsername() + "@" + props.getDomain();
}
/**
* Generate the base users URI
*/
private UriComponentsBuilder getUsersURI() {
return UriComponentsBuilder.newInstance()
.scheme(props.getScheme())
.host(props.getDomain())
.pathSegment("users");
}
/**
* The "id" of a bot (user/actor) is a URI combining domain and username: https://<domain>/users/<username>
*/
public String getId(Bot bot) {
return getUsersURI() + bot.getUsername();
return getUsersURI()
.pathSegment(bot.getUsername())
.toUriString();
}
/**
* The "inbox" of a user is a URI of the form: https://<domain>/users/<username>/inbox
*/
public String getInbox(Bot bot) {
return getUsersURI() + bot.getUsername() + "/inbox";
return getUsersURI()
.pathSegment(bot.getUsername())
.pathSegment("inbox")
.toUriString();
}
/**
* The "outbox" of a user is a URI of the form: https://<domain>/users/<username>/outbox
*/
public String getOutbox(Bot bot) {
return getUsersURI() + bot.getUsername() + "/outbox";
return getUsersURI()
.pathSegment(bot.getUsername())
.pathSegment("outbox")
.toUriString();
}
public Bot save(Bot bot) {

View file

@ -65,14 +65,17 @@ public class RestHandler {
//return new ResponseEntity<>("These are not the droids you are looking for.", HttpStatus.NOT_FOUND);
}
// TODO: So here's a whole other way of generating custom JSON as compared to the BotAPActorJSONSerializer approach
// TODO: So here's a whole other way of generating custom JSON as
// compared to the BotAPActorJSONSerializer approach, should perhaps
// settle on one style of doing it (if we're going to do it either way
// in the end.)
Map<String, Object> response = Map.of(
"subject", bot.getUsername() + "@springbot.seth.id.au",
"subject", botServ.getWebfingerSubject( bot ),
"links", List.of(
Map.of(
"rel", "self",
"type", "application/activity+json",
"href", "https://springbot.seth.id.au/users/" + bot.getUsername()
"href", botServ.getId( bot )
)
)
);

View file

@ -6,6 +6,9 @@ logging.file.name=logs/springbot.log
logging.file.path=logs
spring.output.ansi.enabled=ALWAYS
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
server.tomcat.basedir=logs
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
spring.mvc.view.prefix: /WEB-INF/views/
spring.mvc.view.suffix: .jsp

View file

@ -3,25 +3,21 @@
<head>
<meta charset="ISO-8859-1">
<title>List Bot</title>
<style type="text/css">
span {
display: inline-block;
width: 200px;
text-align: left;
.main {
text-align: center;
}
</style>
</head>
<body>
<div align="center">
<div class="main">
<h2>Pick-a-Bot!</h2>
<ul th:if="${bots.empty}">
<li>No Bots!</li>
</ul>
<th:block th:each="bot : ${bots}">
<span>Bot:</span>
<span><a th:href="@{/viewbot/} + ${bot.username}">[[${bot.username}]]</a></span>
<br>
<th:block th:if="${bots.empty}">
<h3>No Bots!</h3>
</th:block>
<th:block th:each="bot : ${bots}">
<a th:href="@{/viewbot/} + ${bot.username}">[[${@botService.getHandle(bot)}]]</a><br>
</th:block>
<br>
<br>
<a href="/">HOME</a>
</div>

View file

@ -4,24 +4,33 @@
<meta charset="ISO-8859-1">
<title>View Bot</title>
<style type="text/css">
.main {
text-align: center;
}
span {
display: inline-block;
width: 200px;
width: 40em;
text-align: left;
margin-bottom: 0.5em;
}
span.left {
text-align: right;
margin-right: 1em;
}
</style>
</head>
<body>
<div align="center">
<div class="main">
<h2>Bot:</h2>
<span>Username:</span><span th:text="${bot.username}"></span><br/>
<span>Id:</span><span th:text="'@' + ${bot.username} + '@springbot.seth.id.au'"></span><br/>
<span>Display Name:</span><span th:text="${bot.name}"></span><br/>
<span>Description:</span><span th:text="${bot.summary}"></span><br/>
<span>Published:</span><span th:text="${bot.published}"></span><br/>
<span>Type:</span><span th:text="${bot.type}"></span><br/>
<span>Public Key:</span><pre th:text="${bot.getPublicKeyPEMString()}"></pre><br/>
<span class="left">Username:</span><span th:text="${bot.username}"></span><br/>
<span class="left">Id:</span><span th:text="${@botService.getHandle(bot)}"></span><br/>
<span class="left">Display Name:</span><span th:text="${bot.name}"></span><br/>
<span class="left">Description:</span><span th:text="${bot.summary}"></span><br/>
<span class="left">Published:</span><span th:text="${bot.published}"></span><br/>
<span class="left">Type:</span><span th:text="${bot.type}"></span><br/>
<span class="left">Public Key:</span><span></span>
<pre th:text="${bot.getPublicKeyPEMString()}"></pre>
<br>
<br>
<a href="/">HOME</a> |
<a href="/viewbot">Bot List</a>