Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions admin/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ func ModerateHandler(w http.ResponseWriter, r *http.Request) {
<input type="hidden" name="id" value="%s">
<button type="submit" class="btn-approve">Approve</button>
</form>
<form method="POST" action="/admin/moderate" onsubmit="event.preventDefault(); muConfirm('Flag this post?').then(function(ok){if(ok){fetch('/flag',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'same-origin',body:JSON.stringify({type:'post',id:'%s'})}).then(r=>r.json()).then(d=>{if(d.success){location.reload()}else{alert(d.message||'Failed')}}).catch(()=>alert('Error'))}});return false;">
<form method="POST" action="/admin/moderate" onsubmit="event.preventDefault(); muConfirm('Flag this post?').then(function(ok){if(ok){fetch('/admin/flag',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'same-origin',body:JSON.stringify({type:'post',id:'%s'})}).then(r=>r.json()).then(d=>{if(d.success){location.reload()}else{alert(d.message||'Failed')}}).catch(()=>alert('Error'))}});return false;">
<button type="submit" class="btn-delete">Flag</button>
</form>
<a href="/post?id=%s" target="_blank">view</a>
<a href="/blog/post?id=%s" target="_blank">view</a>
</div>
</div>`,
title,
Expand Down
4 changes: 2 additions & 2 deletions blog/activitypub.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,12 @@ func postToObject(base string, acc *auth.Account, post *Post) map[string]interfa

obj := map[string]interface{}{
"@context": "https://www.w3.org/ns/activitystreams",
"id": fmt.Sprintf("%s/post?id=%s", base, post.ID),
"id": fmt.Sprintf("%s/blog/post?id=%s", base, post.ID),
"type": "Note",
"attributedTo": fmt.Sprintf("%s/@%s", base, acc.ID),
"content": rendered,
"published": post.CreatedAt.Format(time.RFC3339),
"url": fmt.Sprintf("%s/post?id=%s", base, post.ID),
"url": fmt.Sprintf("%s/blog/post?id=%s", base, post.ID),
"to": []string{"https://www.w3.org/ns/activitystreams#Public"},
}

Expand Down
4 changes: 2 additions & 2 deletions blog/activitypub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ func TestPostToObject(t *testing.T) {
if obj["type"] != "Note" {
t.Errorf("type = %v, want Note", obj["type"])
}
if obj["id"] != "https://mu.xyz/post?id=123" {
t.Errorf("id = %v, want https://mu.xyz/post?id=123", obj["id"])
if obj["id"] != "https://mu.xyz/blog/post?id=123" {
t.Errorf("id = %v, want https://mu.xyz/blog/post?id=123", obj["id"])
}
if obj["attributedTo"] != "https://mu.xyz/@alice" {
t.Errorf("attributedTo = %v, want https://mu.xyz/@alice", obj["attributedTo"])
Expand Down
54 changes: 27 additions & 27 deletions blog/blog.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func Load() {
post.Title,
post.Content,
map[string]interface{}{
"url": "/post?id=" + post.ID,
"url": "/blog/post?id=" + post.ID,
"author": post.Author,
"tags": post.Tags,
},
Expand Down Expand Up @@ -247,7 +247,7 @@ func Load() {
post.Title,
post.Content,
map[string]interface{}{
"url": "/post?id=" + post.ID,
"url": "/blog/post?id=" + post.ID,
"author": post.Author,
"tags": post.Tags,
},
Expand Down Expand Up @@ -430,9 +430,9 @@ func updateCacheUnlocked() {
commentCount := countComments(post)
replyLink := ""
if commentCount == 0 {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comment</a>`, post.ID)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comment</a>`, post.ID)
} else {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
}

previewTime := post.CreatedAt
Expand All @@ -444,7 +444,7 @@ func updateCacheUnlocked() {

item := fmt.Sprintf(`<div class="post-item">
%s
<h3><a href="/post?id=%s">%s</a></h3>
<h3><a href="/blog/post?id=%s">%s</a></h3>
<div class="info"><span data-timestamp="%d">%s</span> · %s%s</div>
<div>%s</div>
</div>`, tagsHtml, post.ID, title, previewTime.Unix(), previewTimeLabel, authorLink, replyLink, content)
Expand Down Expand Up @@ -528,14 +528,14 @@ func updateCacheUnlocked() {
commentCount := countComments(post)
replyLink := ""
if commentCount == 0 {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comment</a>`, post.ID)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comment</a>`, post.ID)
} else {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
}

keepReading := ""
if truncated {
keepReading = fmt.Sprintf(`<a href="/post?id=%s" class="keep-reading">Keep Reading →</a>`, post.ID)
keepReading = fmt.Sprintf(`<a href="/blog/post?id=%s" class="keep-reading">Keep Reading →</a>`, post.ID)
}

listTime := post.CreatedAt
Expand All @@ -547,7 +547,7 @@ func updateCacheUnlocked() {

item := fmt.Sprintf(`<div class="post-item">
%s
<h3><a href="/post?id=%s">%s</a></h3>
<h3><a href="/blog/post?id=%s">%s</a></h3>
<div class="info"><span data-timestamp="%d">%s</span> · %s%s</div>
<div>%s</div>
%s
Expand Down Expand Up @@ -627,9 +627,9 @@ func previewUncached() string {
commentCount := countComments(post)
replyLink := ""
if commentCount == 0 {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comment</a>`, post.ID)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comment</a>`, post.ID)
} else {
replyLink = fmt.Sprintf(` · <a href="/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
replyLink = fmt.Sprintf(` · <a href="/blog/post?id=%s">Comments (%d)</a>`, post.ID, commentCount)
}

// Generate fresh timestamp
Expand All @@ -639,7 +639,7 @@ func previewUncached() string {
}

item := fmt.Sprintf(`<div class="post-item">
<h3><a href="/post?id=%s">%s</a></h3>
<h3><a href="/blog/post?id=%s">%s</a></h3>
<div>%s</div>
<div class="info">%s · %s%s%s</div>
</div>`, post.ID, title, content, listTimeInfo, authorLink, tagsHtml, replyLink)
Expand Down Expand Up @@ -679,12 +679,12 @@ func renderPostPreview(post *Post) string {
}

item := fmt.Sprintf(`<div class="post-item">
<h3><a href="/post?id=%s">%s</a></h3>
<h3><a href="/blog/post?id=%s">%s</a></h3>
<div class="mb-3">%s</div>
<div class="info">
%s
<span class="ml-3">·</span>
<a href="/post?id=%s" class="ml-3">Comment</a>
<a href="/blog/post?id=%s" class="ml-3">Comment</a>
</div>
</div>`, post.ID, title, content, authorLink, post.ID)

Expand Down Expand Up @@ -941,7 +941,7 @@ func CreatePost(title, content, author, authorID, tags string, private bool) err
title,
content,
map[string]interface{}{
"url": "/post?id=" + id,
"url": "/blog/post?id=" + id,
"author": author,
"tags": tags,
},
Expand Down Expand Up @@ -1079,7 +1079,7 @@ func UpdatePost(id, title, content, tags string, private bool) error {
title,
content,
map[string]interface{}{
"url": "/post?id=" + id,
"url": "/blog/post?id=" + id,
"author": author,
"tags": tags,
},
Expand Down Expand Up @@ -1135,8 +1135,8 @@ func FindTodayDigest() *Post {
// PostHandler serves individual blog posts (public, no auth required) and handles PATCH for editing
// Supports both HTML and JSON requests
func PostHandler(w http.ResponseWriter, r *http.Request) {
// Support both /post/{id} path style and /post?id={id} query style
id := strings.TrimPrefix(r.URL.Path, "/post/")
// Support both /blog/post/{id} path style and /blog/post?id={id} query style
id := strings.TrimPrefix(r.URL.Path, "/blog/post/")
if id == "" || id == r.URL.Path {
id = r.URL.Query().Get("id")
}
Expand Down Expand Up @@ -1338,7 +1338,7 @@ func PostHandler(w http.ResponseWriter, r *http.Request) {
return
}

http.Redirect(w, r, "/post?id="+id, http.StatusSeeOther)
http.Redirect(w, r, "/blog/post?id="+id, http.StatusSeeOther)
return
}

Expand Down Expand Up @@ -1408,7 +1408,7 @@ func PostHandler(w http.ResponseWriter, r *http.Request) {
}

content := fmt.Sprintf(`<div id="blog">
<form method="POST" action="/post?id=%s" class="blog-form">
<form method="POST" action="/blog/post?id=%s" class="blog-form">
<input type="hidden" name="_method" value="PATCH">
<input type="text" name="title" placeholder="Title (optional)" value="%s">
<textarea name="content" rows="15" required>%s</textarea>
Expand All @@ -1422,7 +1422,7 @@ func PostHandler(w http.ResponseWriter, r *http.Request) {
</div>
<div class="blog-form-actions">
<button type="submit">Save Changes</button>
<a href="/post?id=%s" class="btn btn-secondary">Cancel</a>
<a href="/blog/post?id=%s" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>`, post.ID, post.Title, post.Content, post.Tags, publicSelected, privateSelected, post.ID)
Expand All @@ -1449,7 +1449,7 @@ func PostHandler(w http.ResponseWriter, r *http.Request) {
var editButton string
_, acc := auth.TrySession(r)
if acc != nil && acc.ID == post.AuthorID {
editButton = ` · <a href="/post?id=` + post.ID + `&edit=true" class="text-muted">Edit</a> · <a href="#" onclick="if(confirm('Delete this post?')){var f=document.createElement('form');f.method='POST';f.action='/post?id=` + post.ID + `';var i=document.createElement('input');i.type='hidden';i.name='_method';i.value='DELETE';f.appendChild(i);document.body.appendChild(f);f.submit();}return false;" class="text-error">Delete</a>`
editButton = ` · <a href="/blog/post?id=` + post.ID + `&edit=true" class="text-muted">Edit</a> · <a href="#" onclick="if(confirm('Delete this post?')){var f=document.createElement('form');f.method='POST';f.action='/post?id=` + post.ID + `';var i=document.createElement('input');i.type='hidden';i.name='_method';i.value='DELETE';f.appendChild(i);document.body.appendChild(f);f.submit();}return false;" class="text-error">Delete</a>`
}

tagsHtml := ""
Expand Down Expand Up @@ -1518,7 +1518,7 @@ func renderComments(postID string, r *http.Request) string {

if isAuthenticated {
commentsHTML.WriteString(fmt.Sprintf(`
<form method="POST" action="/post/%s/comment" class="blog-form my-5">
<form method="POST" action="/blog/post/%s/comment" class="blog-form my-5">
<textarea name="content" rows="3" placeholder="Add a comment..." required></textarea>
<div>
<button type="submit">Add Comment</button>
Expand Down Expand Up @@ -1710,7 +1710,7 @@ func handlePost(w http.ResponseWriter, r *http.Request) {

// CommentHandler handles comment submissions
func CommentHandler(w http.ResponseWriter, r *http.Request) {
// Only handle /post/{postID}/comment paths
// Only handle /blog/post/{postID}/comment paths
if !strings.Contains(r.URL.Path, "/comment") {
// Not a comment path, pass through to PostHandler
PostHandler(w, r)
Expand All @@ -1730,8 +1730,8 @@ func CommentHandler(w http.ResponseWriter, r *http.Request) {
}
_ = sess // used for consistency

// Extract post ID from URL path (/post/{postID}/comment)
path := strings.TrimPrefix(r.URL.Path, "/post/")
// Extract post ID from URL path (/blog/post/{postID}/comment)
path := strings.TrimPrefix(r.URL.Path, "/blog/post/")
path = strings.TrimSuffix(path, "/comment")
postID := path

Expand Down Expand Up @@ -1764,5 +1764,5 @@ func CommentHandler(w http.ResponseWriter, r *http.Request) {
}

// Redirect back to the post
http.Redirect(w, r, "/post?id="+postID, http.StatusSeeOther)
http.Redirect(w, r, "/blog/post?id="+postID, http.StatusSeeOther)
}
6 changes: 3 additions & 3 deletions chat/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func getOrCreateRoom(id string) *Room {
// Create room with minimal context
room.Title = "Post Discussion"
room.Summary = "Loading post content..."
room.URL = "/post?id=" + itemID
room.URL = "/blog/post?id=" + itemID
break
}

Expand All @@ -308,12 +308,12 @@ func getOrCreateRoom(id string) *Room {
if len(room.Summary) > 2000 {
room.Summary = room.Summary[:2000] + "..."
}
room.URL = "/post?id=" + itemID
room.URL = "/blog/post?id=" + itemID
app.Log("chat", "Room context - Title: %s, Summary length: %d, URL: %s", room.Title, len(room.Summary), room.URL)
} else if room.Title == "" {
app.Log("chat", "Post %s not found in index", itemID)
room.Title = "Post Discussion"
room.URL = "/post?id=" + itemID
room.URL = "/blog/post?id=" + itemID
}
case "news":
// For news, lookup by exact ID
Expand Down
2 changes: 1 addition & 1 deletion home/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ Accept: application/json</pre>
var age=ts?'<span style="font-size:11px;color:#888;">'+timeAgo(ts)+'</span>':'';
var tag=(opinion.tags||'').indexOf('opinion')!==-1?'<span style="font-size:11px;background:#f0f0f0;padding:2px 8px;border-radius:10px;margin-right:6px;">opinion</span>':'';
el.innerHTML='<div style="padding:8px 0;">'+tag+age+
'<a href="/post/'+esc(opinion.id)+'" style="font-size:15px;font-weight:700;display:block;line-height:1.4;margin-top:4px;color:#111;">'+esc(title)+'</a>'+
'<a href="/blog/post/'+esc(opinion.id)+'" style="font-size:15px;font-weight:700;display:block;line-height:1.4;margin-top:4px;color:#111;">'+esc(title)+'</a>'+
'<p style="font-size:13px;color:#555;line-height:1.5;margin-top:6px;">'+esc(content)+'</p>'+
'</div>';
})
Expand Down
12 changes: 6 additions & 6 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ var Endpoints = []*Endpoint{{
},
}, {
Name: "Get Post",
Path: "/post/{id}",
Path: "/blog/post/{id}",
Method: "GET",
Description: "Get a single blog post by ID",
Response: []*Value{
Expand Down Expand Up @@ -174,7 +174,7 @@ var Endpoints = []*Endpoint{{
},
}, {
Name: "Update Post",
Path: "/post/{id}",
Path: "/blog/post/{id}",
Method: "PATCH",
Description: "Update an existing blog post (author only)",
Params: []*Param{
Expand Down Expand Up @@ -208,7 +208,7 @@ var Endpoints = []*Endpoint{{
},
}, {
Name: "Create Post",
Path: "/post",
Path: "/blog/post",
Method: "POST",
Description: "Create a new blog post",
Params: []*Param{
Expand Down Expand Up @@ -419,7 +419,7 @@ func init() {

Endpoints = append(Endpoints, &Endpoint{
Name: "Delete Post",
Path: "/post/{id}",
Path: "/blog/post/{id}",
Method: "DELETE",
Description: "Delete a blog post (author only)",
Response: []*Value{
Expand Down Expand Up @@ -483,7 +483,7 @@ func init() {

Endpoints = append(Endpoints, &Endpoint{
Name: "Add Comment",
Path: "/post/{id}/comment",
Path: "/blog/post/{id}/comment",
Method: "POST",
Description: "Add a comment to a blog post",
Params: []*Param{
Expand Down Expand Up @@ -536,7 +536,7 @@ func init() {
// Flag endpoint
Endpoints = append(Endpoints, &Endpoint{
Name: "Flag Content",
Path: "/flag",
Path: "/admin/flag",
Method: "POST",
Description: "Flag inappropriate content",
Params: []*Param{
Expand Down
8 changes: 4 additions & 4 deletions internal/api/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ var tools = []Tool{
Name: "blog_read",
Description: "Read a specific blog post by ID",
Method: "GET",
Path: "/post",
Path: "/blog/post",
Params: []ToolParam{
{Name: "id", Type: "string", Description: "The blog post ID", Required: true},
},
Expand All @@ -177,7 +177,7 @@ var tools = []Tool{
Name: "blog_create",
Description: "Create a new blog post",
Method: "POST",
Path: "/post",
Path: "/blog/post",
WalletOp: "blog_create",
Params: []ToolParam{
{Name: "title", Type: "string", Description: "Post title", Required: false},
Expand All @@ -188,7 +188,7 @@ var tools = []Tool{
Name: "blog_update",
Description: "Update an existing blog post (author only)",
Method: "PATCH",
Path: "/post",
Path: "/blog/post",
Params: []ToolParam{
{Name: "id", Type: "string", Description: "The blog post ID to update", Required: true},
{Name: "title", Type: "string", Description: "New post title", Required: false},
Expand All @@ -199,7 +199,7 @@ var tools = []Tool{
Name: "blog_delete",
Description: "Delete a blog post (author only)",
Method: "DELETE",
Path: "/post",
Path: "/blog/post",
Params: []ToolParam{
{Name: "id", Type: "string", Description: "The blog post ID to delete", Required: true},
},
Expand Down
8 changes: 4 additions & 4 deletions internal/app/ui_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ func TestTags_WithoutBaseURL(t *testing.T) {
}

func TestTitle_WithHref(t *testing.T) {
result := Title("My Post", "/post/1")
if !strings.Contains(result, `href="/post/1"`) {
result := Title("My Post", "/blog/post/1")
if !strings.Contains(result, `href="/blog/post/1"`) {
t.Error("expected link")
}
if !strings.Contains(result, "My Post") {
Expand Down Expand Up @@ -263,7 +263,7 @@ func TestItemMeta_AllEmpty(t *testing.T) {
}

func TestDeleteButton(t *testing.T) {
result := DeleteButton("/post/1", "Remove", "Delete this?")
result := DeleteButton("/blog/post/1", "Remove", "Delete this?")
if !strings.Contains(result, "Delete this?") {
t.Error("expected custom confirm message")
}
Expand All @@ -273,7 +273,7 @@ func TestDeleteButton(t *testing.T) {
}

func TestDeleteButton_Defaults(t *testing.T) {
result := DeleteButton("/post/1", "", "")
result := DeleteButton("/blog/post/1", "", "")
if !strings.Contains(result, "Delete") {
t.Error("expected default label 'Delete'")
}
Expand Down
Loading
Loading