back interdiff of round #2 and #1

feat: add language statistics to repo page #208

files
appview
knotserver
types
ERROR
knotserver/routes.go

Failed to calculate interdiff for this file.

ERROR
types/repo.go

Failed to calculate interdiff for this file.

ERROR
appview/pages/templates/layouts/repobase.html

Failed to calculate interdiff for this file.

REVERTED
appview/pages/templates/settings.html
···
<form
hx-delete="/settings/emails"
hx-confirm="Are you sure you wish to delete the email '{{ .Address }}'?"
+
hx-indicator="#delete-email-{{ .Address }}-spinner"
-
hx-indicator="#delete-email-{{ $index }}-spinner"
>
<input type="hidden" name="email" value="{{ .Address }}">
<button
···
>
{{ i "trash-2" "w-5 h-5" }}
<span class="hidden md:inline">delete</span>
+
<span id="delete-email-{{ .Address }}-spinner" class="group">
-
<span id="delete-email-{{ $index }}-spinner" class="group">
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
</span>
</button>
REVERTED
appview/repo/repo_util.go
···
"context"
"crypto/rand"
"fmt"
+
"log"
"math/big"
"github.com/go-git/go-git/v5/plumbing/object"
+
"tangled.sh/tangled.sh/core/appview/db"
+
"tangled.sh/tangled.sh/core/crypto"
+
"tangled.sh/tangled.sh/core/types"
)
func uniqueEmails(commits []*object.Commit) []string {
···
return emailToDidOrHandle
}
+
func verifiedObjectCommits(r *Repo, emailToDid map[string]string, commits []*object.Commit) (map[string]bool, error) {
+
ndCommits := []types.NiceDiff{}
+
for _, commit := range commits {
+
ndCommits = append(ndCommits, types.ObjectCommitToNiceDiff(commit))
+
}
+
return verifiedCommits(r, emailToDid, ndCommits)
+
}
+
+
func verifiedCommits(r *Repo, emailToDid map[string]string, ndCommits []types.NiceDiff) (map[string]bool, error) {
+
hashToVerified := make(map[string]bool)
+
+
didPubkeyCache := make(map[string][]db.PublicKey)
+
+
for _, commit := range ndCommits {
+
c := commit.Commit
+
+
committerEmail := c.Committer.Email
+
if did, exists := emailToDid[committerEmail]; exists {
+
// check if we've already fetched public keys for this did
+
pubKeys, ok := didPubkeyCache[did]
+
if !ok {
+
// fetch and cache public keys
+
keys, err := db.GetPublicKeysForDid(r.db, did)
+
if err != nil {
+
log.Printf("failed to fetch pubkey for %s: %v", committerEmail, err)
+
continue
+
}
+
pubKeys = keys
+
didPubkeyCache[did] = pubKeys
+
}
+
+
verified := false
+
+
// try to verify with any associated pubkeys
+
for _, pk := range pubKeys {
+
if _, ok := crypto.VerifyCommitSignature(pk.Key, commit); ok {
+
verified = true
+
break
+
}
+
}
+
+
hashToVerified[c.This] = verified
+
}
+
}
+
+
return hashToVerified, nil
+
}
+
func randomString(n int) string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
result := make([]byte, n)
REVERTED
types/diff.go
···
return files
}
+
+
// ObjectCommitToNiceDiff is a compatibility function to convert a
+
// commit object into a NiceDiff structure.
+
func ObjectCommitToNiceDiff(c *object.Commit) NiceDiff {
+
var niceDiff NiceDiff
+
+
// set commit information
+
niceDiff.Commit.Message = c.Message
+
niceDiff.Commit.Author = c.Author
+
niceDiff.Commit.This = c.Hash.String()
+
niceDiff.Commit.Committer = c.Committer
+
niceDiff.Commit.Tree = c.TreeHash.String()
+
niceDiff.Commit.PGPSignature = c.PGPSignature
+
+
changeId, ok := c.ExtraHeaders["change-id"]
+
if ok {
+
niceDiff.Commit.ChangedId = string(changeId)
+
}
+
+
// set parent hash if available
+
if len(c.ParentHashes) > 0 {
+
niceDiff.Commit.Parent = c.ParentHashes[0].String()
+
}
+
+
// XXX: Stats and Diff fields are typically populated
+
// after fetching the actual diff information, which isn't
+
// directly available in the commit object itself.
+
+
return niceDiff
+
}
REVERTED
appview/pages/templates/repo/log.html
···
{{ define "extrameta" }}
{{ $title := printf "commits &middot; %s" .RepoInfo.FullName }}
{{ $url := printf "https://tangled.sh/%s/commits" .RepoInfo.FullName }}
+
-
{{ template "repo/fragments/og" (dict "RepoInfo" .RepoInfo "Title" $title "Url" $url) }}
{{ end }}
{{ define "repoContent" }}
<section id="commit-table" class="overflow-x-auto">
<h2 class="font-bold text-sm mb-4 uppercase dark:text-white">
+
commits
-
commits
</h2>
<!-- desktop view (hidden on small screens) -->
···
{{ end }}
</td>
<td class="py-3 align-top font-mono flex items-center">
+
{{ $verified := false }}
+
{{ $verified = index $.VerifiedCommits $commit.Hash.String }}
-
{{ $verified := $.VerifiedCommits.IsVerified $commit.Hash.String }}
{{ $hashStyle := "text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-900" }}
{{ if $verified }}
{{ $hashStyle = "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 px-2 rounded" }}
···
{{ end }}
</a>
<div class="{{ if not $verified }} ml-6 {{ end }}inline-flex">
+
<button class="p-1 mx-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
-
<button class="p-1 mx-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
title="Copy SHA"
onclick="navigator.clipboard.writeText('{{ $commit.Hash.String }}'); this.innerHTML=`{{ i "copy-check" "w-4 h-4" }}`; setTimeout(() => this.innerHTML=`{{ i "copy" "w-4 h-4" }}`, 1500)">
{{ i "copy" "w-4 h-4" }}
···
<div>
<div class="flex items-center justify-start">
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ $commit.Hash.String }}" class="dark:text-white no-underline hover:underline">{{ index $messageParts 0 }}</a>
+
{{ if gt (len $messageParts) 1 }}
-
{{ if gt (len $messageParts) 1 }}
<button class="ml-2 py-1/2 px-1 bg-gray-200 hover:bg-gray-400 dark:bg-gray-700 dark:hover:bg-gray-600 rounded" hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')">{{ i "ellipsis" "w-3 h-3" }}</button>
{{ end }}
+
-
{{ if index $.TagMap $commit.Hash.String }}
{{ range $tag := index $.TagMap $commit.Hash.String }}
<span class="ml-2 text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 inline-flex items-center">
···
</span>
{{ end }}
{{ end }}
+
-
</div>
+
-
{{ if gt (len $messageParts) 1 }}
<p class="hidden mt-1 text-sm text-gray-600 dark:text-gray-400">{{ nl2br (index $messageParts 1) }}</p>
{{ end }}
···
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="inline">
+
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ $commit.Hash.String }}"
-
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ $commit.Hash.String }}"
class="inline no-underline hover:underline dark:text-white">
{{ index $messageParts 0 }}
</a>
{{ if gt (len $messageParts) 1 }}
+
<button
-
<button
class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600 ml-2"
hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')">
{{ i "ellipsis" "w-3 h-3" }}
···
</p>
{{ end }}
</div>
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ $commit.Hash.String }}"
+
class="p-1 mr-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
-
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ $commit.Hash.String }}"
-
class="p-1 mr-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
title="Browse repository at this commit">
{{ i "folder-code" "w-4 h-4" }}
</a>
···
</div>
<div class="text-xs mt-2 text-gray-500 dark:text-gray-400 flex items-center">
+
{{ $verified := false }}
+
{{ $verified = index $.VerifiedCommits $commit.Hash.String }}
-
{{ $verified := $.VerifiedCommits.IsVerified $commit.Hash.String }}
{{ $hashStyle := "text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-900" }}
{{ if $verified }}
{{ $hashStyle = "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 px-2 rounded" }}
REVERTED
appview/config/config.go
···
}
type ResendConfig struct {
+
ApiKey string `env:"API_KEY"`
-
ApiKey string `env:"API_KEY"`
-
SentFrom string `env:"SENT_FROM, default=noreply@notifs.tangled.sh"`
}
type CamoConfig struct {
REVERTED
appview/settings/settings.go
···
return email.Email{
APIKey: s.Config.Resend.ApiKey,
+
From: "noreply@notifs.tangled.sh",
-
From: s.Config.Resend.SentFrom,
To: emailAddr,
Subject: "Verify your Tangled email",
Text: `Click the link below (or copy and paste it into your browser) to verify your email address.
ERROR
appview/repo/repo.go

Failed to calculate interdiff for this file.

REVERTED
go.mod
···
github.com/go-git/go-git/v5 v5.14.0
github.com/google/uuid v1.6.0
github.com/gorilla/sessions v1.4.0
-
github.com/gorilla/websocket v1.5.3
github.com/hiddeco/sshsig v0.2.0
github.com/ipfs/go-cid v0.5.0
github.com/lestrrat-go/jwx/v2 v2.1.6
···
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
+
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
···
replace github.com/bluekeyes/go-gitdiff => tangled.sh/oppi.li/go-gitdiff v0.8.2
+
replace github.com/alecthomas/chroma/v2 => github.com/oppiliappan/chroma/v2 v2.17.0
-
replace github.com/alecthomas/chroma/v2 => github.com/oppiliappan/chroma/v2 v2.19.0
// from bluesky-social/indigo
replace github.com/gocql/gocql => github.com/scylladb/gocql v1.14.4
REVERTED
go.sum
···
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+
github.com/oppiliappan/chroma/v2 v2.17.0 h1:Qi8qnCvhCn8VxwD+BGpt7n5BdLX32/2kRBlT7hAR5Ko=
+
github.com/oppiliappan/chroma/v2 v2.17.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
-
github.com/oppiliappan/chroma/v2 v2.19.0 h1:PN7/pb+6JRKCva30NPTtRJMlrOyzgpPpIroNzy4ekHU=
-
github.com/oppiliappan/chroma/v2 v2.19.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
github.com/oppiliappan/go-git/v5 v5.17.0 h1:CuJnpcIDxr0oiNaSHMconovSWnowHznVDG+AhjGuSEo=
github.com/oppiliappan/go-git/v5 v5.17.0/go.mod h1:q/FE8C3SPMoRN7LoH9vRFiBzidAOBWJPS1CqVS8DN+w=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
NEW
appview/pages/pages.go
···
Raw bool
EmailToDidOrHandle map[string]string
VerifiedCommits commitverify.VerifiedCommits
-
Languages *types.RepoLanguageResponse
+
Languages []types.RepoLanguageDetails
types.RepoIndexResponse
}
NEW
appview/pages/templates/repo/index.html
···
{{ template "repo/fragments/og" (dict "RepoInfo" .RepoInfo) }}
{{ end }}
+
{{ define "repoLanguages" }}
+
<div class="flex gap-[3px]">
+
{{ range $value := .Languages }}
+
<div
+
title="{{ $value.Name }} {{ printf "%.1f" $value.Percentage }}%"
+
class="h-2"
+
style="background-color: {{ $value.Color }}; width: {{ $value.Percentage }}%"
+
></div>
+
{{ end }}
+
</div>
+
{{ end }}
{{ define "repoContent" }}
<main>