An implementation of the ATProto statusphere example app but in Go
at test 3.3 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 slog.Info("session", "did", did.String(), "session id", sessionID) 118 119 oauthSess, err := s.oauthClient.ResumeSession(r.Context(), *did, sessionID) 120 if err != nil { 121 http.Error(w, "not authenticated", http.StatusUnauthorized) 122 return 123 } 124 c := oauthSess.APIClient() 125 126 createdAt := time.Now() 127 128 bodyReq := map[string]any{ 129 "repo": c.AccountDID.String(), 130 "collection": "xyz.statusphere.status", 131 "record": map[string]any{ 132 "status": status, 133 "createdAt": createdAt, 134 }, 135 } 136 var result CreateRecordResp 137 err = c.Post(r.Context(), "com.atproto.repo.createRecord", bodyReq, &result) 138 if err != nil { 139 slog.Error("failed to create new status", "error", err) 140 http.Redirect(w, r, "/", http.StatusFound) 141 return 142 } 143 144 statusToStore := Status{ 145 URI: result.URI, 146 Did: c.AccountDID.String(), 147 Status: status, 148 CreatedAt: createdAt.UnixMilli(), 149 IndexedAt: time.Now().UnixMilli(), 150 } 151 152 err = s.store.CreateStatus(statusToStore) 153 if err != nil { 154 slog.Error("failed to store status that has been created", "error", err) 155 } 156 157 http.Redirect(w, r, "/", http.StatusFound) 158}