An implementation of the ATProto statusphere example app but in Go
at main 3.2 kB view raw
1package statusphere 2 3import ( 4 "fmt" 5 "log/slog" 6 "net/http" 7 "time" 8) 9 10var Availablestatus = []string{ 11 "👍", 12 "👎", 13 "💙", 14 "🥹", 15 "😧", 16 "😤", 17 "🙃", 18 "😉", 19 "😎", 20 "🤓", 21 "🤨", 22 "🥳", 23 "😭", 24 "😤", 25 "🤯", 26 "🫡", 27 "💀", 28 "✊", 29 "🤘", 30 "👀", 31 "🧠", 32 "👩‍💻", 33 "🧑‍💻", 34 "🥷", 35 "🧌", 36 "🦋", 37 "🚀", 38} 39 40type HomeData struct { 41 DisplayName string 42 AvailableStatus []string 43 UsersStatus []UserStatus 44} 45 46type UserStatus struct { 47 Status string 48 Handle string 49 HandleURL string 50 Date string 51 IsToday bool 52} 53 54func (s *Server) HandleHome(w http.ResponseWriter, r *http.Request) { 55 tmpl := s.getTemplate("home.html") 56 data := HomeData{ 57 AvailableStatus: Availablestatus, 58 } 59 60 did, _ := s.currentSessionDID(r) 61 if did != nil { 62 profile, err := s.getUserProfileForDid(did.String()) 63 if err != nil { 64 slog.Error("getting logged in users profile", "error", err) 65 } 66 data.DisplayName = profile.DisplayName 67 } 68 69 today := time.Now().Format(time.DateOnly) 70 71 results, err := s.store.GetStatuses(10) 72 if err != nil { 73 slog.Error("get status'", "error", err) 74 } 75 76 for _, status := range results { 77 date := time.UnixMilli(status.CreatedAt).Format(time.DateOnly) 78 79 profile, err := s.getUserProfileForDid(status.Did) 80 if err != nil { 81 slog.Error("getting user profile for status - skipping", "error", err, "did", status.Did) 82 continue 83 } 84 85 data.UsersStatus = append(data.UsersStatus, UserStatus{ 86 Status: status.Status, 87 Handle: profile.Handle, 88 HandleURL: fmt.Sprintf("https://bsky.app/profile/%s", status.Did), 89 Date: date, 90 IsToday: date == today, 91 }) 92 } 93 94 tmpl.Execute(w, data) 95} 96 97func (s *Server) HandleStatus(w http.ResponseWriter, r *http.Request) { 98 err := r.ParseForm() 99 if err != nil { 100 slog.Error("parsing form", "error", err) 101 http.Error(w, "parsing form", http.StatusBadRequest) 102 return 103 } 104 105 status := r.FormValue("status") 106 if status == "" { 107 http.Error(w, "missing status", http.StatusBadRequest) 108 return 109 } 110 111 did, sessionID := s.currentSessionDID(r) 112 if did == nil { 113 http.Redirect(w, r, "/login", http.StatusFound) 114 return 115 } 116 117 oauthSess, err := s.oauthClient.ResumeSession(r.Context(), *did, sessionID) 118 if err != nil { 119 http.Error(w, "not authenticated", http.StatusUnauthorized) 120 return 121 } 122 c := oauthSess.APIClient() 123 124 createdAt := time.Now() 125 126 bodyReq := map[string]any{ 127 "repo": c.AccountDID.String(), 128 "collection": "xyz.statusphere.status", 129 "record": map[string]any{ 130 "status": status, 131 "createdAt": createdAt, 132 }, 133 } 134 var result CreateRecordResp 135 err = c.Post(r.Context(), "com.atproto.repo.createRecord", bodyReq, &result) 136 if err != nil { 137 slog.Error("failed to create new status", "error", err) 138 http.Redirect(w, r, "/", http.StatusFound) 139 return 140 } 141 142 statusToStore := Status{ 143 URI: result.URI, 144 Did: c.AccountDID.String(), 145 Status: status, 146 CreatedAt: createdAt.UnixMilli(), 147 IndexedAt: time.Now().UnixMilli(), 148 } 149 150 err = s.store.CreateStatus(statusToStore) 151 if err != nil { 152 slog.Error("failed to store status that has been created", "error", err) 153 } 154 155 http.Redirect(w, r, "/", http.StatusFound) 156}