Improve login flow
- on successful login, kick off scraping of logged-in user, their followees, and only-followed home timeline - `--auto-open` flag now opens `/login` instead of home page - add HTMX spinner for login page - provide toast error notification if login is challenged (e.g., 2FA)
This commit is contained in:
parent
2d14621cc0
commit
8255c4f65e
@ -42,12 +42,13 @@ func (app *Application) Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
form.Validate()
|
form.Validate()
|
||||||
if len(form.FormErrors) == 0 {
|
if len(form.FormErrors) == 0 {
|
||||||
api := scraper.NewGuestSession()
|
api := scraper.NewGuestSession()
|
||||||
api.LogIn(form.Username, form.Password)
|
challenge := api.LogIn(form.Username, form.Password)
|
||||||
app.Profile.SaveSession(api)
|
if challenge != nil {
|
||||||
if err := app.SetActiveUser(api.UserHandle); err != nil {
|
panic( // Middleware will trap this panic and return an HTMX error toast
|
||||||
app.ErrorLog.Printf(err.Error())
|
"Twitter challenged your login. Make sure your username is your user handle (not email). " +
|
||||||
|
"If you're logging in from a new device, try doing it on the official Twitter site first, then try again here.")
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/login", 303)
|
app.after_login(w, r, api)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -60,6 +61,46 @@ func (app *Application) Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
app.buffered_render_page(w, "tpl/login.tpl", PageGlobalData{}, &data)
|
app.buffered_render_page(w, "tpl/login.tpl", PageGlobalData{}, &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *Application) after_login(w http.ResponseWriter, r *http.Request, api scraper.API) {
|
||||||
|
app.Profile.SaveSession(api)
|
||||||
|
|
||||||
|
// Ensure the user is downloaded
|
||||||
|
user, err := scraper.GetUser(api.UserHandle)
|
||||||
|
if err != nil {
|
||||||
|
app.error_404(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic_if(app.Profile.SaveUser(&user))
|
||||||
|
panic_if(app.Profile.DownloadUserContentFor(&user))
|
||||||
|
|
||||||
|
// Now that the user is scraped for sure, set them as the logged-in user
|
||||||
|
err = app.SetActiveUser(api.UserHandle)
|
||||||
|
panic_if(err)
|
||||||
|
|
||||||
|
// Scrape the user's feed
|
||||||
|
trove, err := scraper.GetHomeTimeline("", true)
|
||||||
|
if err != nil {
|
||||||
|
app.ErrorLog.Printf("Initial timeline scrape failed: %s", err.Error())
|
||||||
|
http.Redirect(w, r, "/", 303)
|
||||||
|
}
|
||||||
|
fmt.Println("Saving initial feed results...")
|
||||||
|
app.Profile.SaveTweetTrove(trove, false)
|
||||||
|
go app.Profile.SaveTweetTrove(trove, true)
|
||||||
|
|
||||||
|
// Scrape the user's followers
|
||||||
|
trove, err = scraper.GetFollowees(user.ID, 1000)
|
||||||
|
if err != nil {
|
||||||
|
app.ErrorLog.Printf("Failed to scrape followers: %s", err.Error())
|
||||||
|
http.Redirect(w, r, "/", 303)
|
||||||
|
}
|
||||||
|
app.Profile.SaveTweetTrove(trove, false)
|
||||||
|
app.Profile.SaveAsFolloweesList(user.ID, trove)
|
||||||
|
go app.Profile.SaveTweetTrove(trove, true)
|
||||||
|
|
||||||
|
// Redirect to Timeline
|
||||||
|
http.Redirect(w, r, "/", 303)
|
||||||
|
}
|
||||||
|
|
||||||
func (app *Application) ChangeSession(w http.ResponseWriter, r *http.Request) {
|
func (app *Application) ChangeSession(w http.ResponseWriter, r *http.Request) {
|
||||||
app.traceLog.Printf("'change-session' handler (path: %q)", r.URL.Path)
|
app.traceLog.Printf("'change-session' handler (path: %q)", r.URL.Path)
|
||||||
form := struct {
|
form := struct {
|
||||||
|
@ -150,7 +150,7 @@ func (app *Application) Run(address string, should_auto_open bool) {
|
|||||||
app.start_background()
|
app.start_background()
|
||||||
|
|
||||||
if should_auto_open {
|
if should_auto_open {
|
||||||
go openWebPage("http://" + address)
|
go openWebPage("http://" + address + "/login")
|
||||||
}
|
}
|
||||||
err := srv.ListenAndServe()
|
err := srv.ListenAndServe()
|
||||||
app.ErrorLog.Fatal(err)
|
app.ErrorLog.Fatal(err)
|
||||||
|
@ -35,6 +35,11 @@
|
|||||||
<div class="field-container submit-container">
|
<div class="field-container submit-container">
|
||||||
<input type='submit' value='Login'>
|
<input type='submit' value='Login'>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="htmx-spinner-container">
|
||||||
|
<div class="htmx-spinner-background"></div>
|
||||||
|
<img class="svg-icon htmx-spinner" src="/static/icons/spinner.svg" />
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user