|
1 |
| -//Versão 1.0 |
2 |
| -//Program to find what is your class |
3 | 1 | package main
|
4 | 2 |
|
5 | 3 | import (
|
6 | 4 | "encoding/json"
|
7 |
| - "fmt" |
| 5 | + "errors" |
8 | 6 | "io/ioutil"
|
9 | 7 | "net/http"
|
10 | 8 | "os"
|
11 | 9 | "strings"
|
12 | 10 |
|
13 |
| - "github.com/gonutz/w32/v2" |
14 |
| - "github.com/ncruces/zenity" |
| 11 | + "github.com/alternativeon/pgo" |
| 12 | + "github.com/andlabs/ui" |
| 13 | + "github.com/mattn/go-colorable" |
| 14 | + "github.com/rs/zerolog" |
| 15 | + llgg "github.com/rs/zerolog/log" |
15 | 16 | )
|
16 | 17 |
|
17 |
| -type Token struct { |
18 |
| - AccessToken string `json:"access_token"` |
19 |
| - RefreshToken string `json:"refresh_token"` |
20 |
| - ExpiresIn int `json:"expires_in"` |
21 |
| - TokenType string `json:"token_type"` |
22 |
| - JSON string `json:"json"` |
23 |
| -} |
24 |
| - |
25 |
| -type Error struct { |
26 |
| - Error string `json:"error"` |
27 |
| - ErrorDescription string `json:"error_description"` |
28 |
| -} |
| 18 | +var mainwin *ui.Window |
29 | 19 |
|
30 |
| -type AutoGenerated []struct { |
| 20 | +type UserClass []struct { |
31 | 21 | Value string `json:"value"`
|
32 | 22 | Label string `json:"label"`
|
33 | 23 | Turmas []Turmas `json:"turmas"`
|
34 | 24 | }
|
| 25 | + |
35 | 26 | type Turmas struct {
|
36 | 27 | NomeTurma string `json:"nomeTurma"`
|
37 | 28 | TurmaValida bool `json:"turmaValida"`
|
38 | 29 | NomeSerie string `json:"nomeSerie"`
|
39 | 30 | }
|
40 | 31 |
|
41 |
| -func main() { |
42 |
| - //Dialog asking for the username and password |
43 |
| - user, err := zenity.Entry("Qual o seu usuário do Positivo On?", zenity.Title("Descubra sua turma"), zenity.EntryText("Usuário")) |
44 |
| - if err != nil { |
45 |
| - fmt.Println("[i] {username}", err) |
46 |
| - os.Exit(0) |
47 |
| - } |
48 |
| - if user == "" { |
49 |
| - zenity.Error("Usuário não informado", zenity.Title("Erro"), zenity.ErrorIcon) |
50 |
| - fmt.Println("[w] Usuário não informado") |
51 |
| - main() |
52 |
| - } |
53 |
| - _, pass, err := zenity.Password(zenity.Title("Qual a sua senha do Positivo On?")) |
54 |
| - if err != nil { |
55 |
| - fmt.Println("[i] {password}", err) |
56 |
| - os.Exit(0) |
57 |
| - } |
58 |
| - if pass == "" { |
59 |
| - zenity.Error("Senha não informada", zenity.Title("Erro"), zenity.ErrorIcon) |
60 |
| - fmt.Println("[w] Senha não informada") |
61 |
| - main() |
62 |
| - } |
63 |
| - //Do a x-www-form-urlencoded request to https://sso.specomunica.com.br/connect/token using requests package |
64 |
| - token, err := postReq("https://sso.specomunica.com.br/connect/token", "POST", "username="+user+"&password="+pass+"&grant_type=password&client_id=hubpsd&client_secret=DA5730D8-90FF-4A41-BFED-147B8E0E2A08&scope=openid%20offline_access%20integration_info") |
65 |
| - if err != nil { |
66 |
| - fmt.Println("[E] Login falhou", err) |
67 |
| - os.Exit(1) |
68 |
| - } |
69 |
| - //do a GET request to https://apihub.positivoon.com.br/api/NivelEnsino?usuarioId=1485 using bearer token |
70 |
| - turma, err := authReq("https://apihub.positivoon.com.br/api/NivelEnsino?usuarioId=1485", "GET", token) |
71 |
| - if err != nil { |
72 |
| - fmt.Println("[E] Erro ao buscar turma", err) |
73 |
| - os.Exit(1) |
74 |
| - } |
75 |
| - //Unmarshal response |
| 32 | +func init() { |
| 33 | + //Configuração do logger |
| 34 | + logOutput := colorable.NewColorableStdout() |
| 35 | + llgg.Logger = llgg.Output(zerolog.ConsoleWriter{Out: logOutput}) |
| 36 | +} |
76 | 37 |
|
77 |
| - var turmaAutoGenerated AutoGenerated |
78 |
| - err = json.Unmarshal([]byte(turma), &turmaAutoGenerated) |
79 |
| - if err != nil { |
80 |
| - fmt.Println("[E] Erro ao deserializar", err) |
81 |
| - os.Exit(1) |
82 |
| - } |
83 |
| - //Print nome da turma |
84 |
| - fmt.Println("[i] Sua turma é:", turmaAutoGenerated[0].Value) |
85 |
| - //Print nome da série |
86 |
| - fmt.Println("[i] Sua série é:", turmaAutoGenerated[0].Label) |
87 |
| - //Print nome da turma |
88 |
| - fmt.Println("[i] Sua turma é:", turmaAutoGenerated[0].Turmas[0].NomeTurma) |
89 |
| - //Print nome da série |
90 |
| - fmt.Println("[i] Sua série é:", turmaAutoGenerated[0].Turmas[0].NomeSerie) |
91 |
| - //Print nome da turma |
92 |
| - fmt.Println("[i] Sua turma é:", turmaAutoGenerated[0].Turmas[0].TurmaValida) |
93 |
| - zenity.Info("Sua turma é: "+turmaAutoGenerated[0].Turmas[0].NomeTurma+" ("+turmaAutoGenerated[0].Label+" - "+turmaAutoGenerated[0].Value+""+turmaAutoGenerated[0].Turmas[0].NomeSerie+")", zenity.Title("Sucesso! Sua turma é:"), zenity.InfoIcon) |
94 |
| - //Ask if you want to see another project in github |
95 |
| - openBrowser := zenity.Question("Deseja ver um cliente alternativo ao Positivo On?", zenity.Title("Deseja ver um cliente alternativo ao Positivo On?"), zenity.QuestionIcon) |
96 |
| - switch { |
97 |
| - case openBrowser != zenity.ErrCanceled: |
98 |
| - //Open link in browser |
99 |
| - err := w32.ShellExecute(0, "open", "https://github.com/PrincessMortix/AlternativeOn", "", "", w32.SW_SHOW) |
| 38 | +func loginPage() ui.Control { |
| 39 | + //Cria a UI de login |
| 40 | + vbox := ui.NewVerticalBox() |
| 41 | + vbox.SetPadded(true) |
| 42 | + vbox.Append(ui.NewLabel("Para começarmos, faça seu login. Use o usuário e senha do Positivo On"), false) |
| 43 | + vbox.Append(ui.NewVerticalSeparator(), false) |
| 44 | + |
| 45 | + group := ui.NewGroup("Login") |
| 46 | + group.SetMargined(true) |
| 47 | + vbox.Append(group, true) |
| 48 | + |
| 49 | + aboutform := ui.NewForm() |
| 50 | + aboutform.SetPadded(true) |
| 51 | + group.SetChild(aboutform) |
| 52 | + |
| 53 | + //aboutform.Append("Usuário", ui.NewEntry(), false) |
| 54 | + user := ui.NewEntry() |
| 55 | + user.SetText("") |
| 56 | + aboutform.Append("Usuário", user, false) |
| 57 | + pass := ui.NewPasswordEntry() |
| 58 | + pass.SetText("") |
| 59 | + aboutform.Append("Senha", pass, false) |
| 60 | + loginButton := ui.NewButton("Entrar") |
| 61 | + loginButton.OnClicked(func(*ui.Button) { |
| 62 | + //disable button |
| 63 | + loginButton.Disable() |
| 64 | + //get user and password |
| 65 | + user := user.Text() |
| 66 | + pass := pass.Text() |
| 67 | + //check if user and password are empty |
| 68 | + if user == "" || pass == "" { |
| 69 | + llgg.Error().Msg("Usuário tentou fazer login sem preencher os dados necessários.") |
| 70 | + //error message |
| 71 | + ui.MsgBoxError(mainwin, "Preencha todos os campos", "O campo de usuário e senha não podem ser vazios.") |
| 72 | + loginButton.Enable() |
| 73 | + return |
| 74 | + } |
| 75 | + //do login |
| 76 | + llgg.Trace().Msg("Iniciando login...") |
| 77 | + |
| 78 | + usrtoken, err := pgo.Login(user, pass) |
100 | 79 | if err != nil {
|
101 |
| - fmt.Println("[E]", err) |
| 80 | + llgg.Error().Str("Detalhes", err.Error()).Msg("Erro ao fazer login!") |
| 81 | + ui.MsgBoxError(mainwin, "Erro ao realizar a autenticação!", err.Error()) |
| 82 | + loginButton.Enable() |
| 83 | + return |
102 | 84 | }
|
103 |
| - default: |
104 |
| - os.Exit(0) |
105 |
| - } |
| 85 | + llgg.Info().Msg("Login realizado com sucesso!") |
| 86 | + llgg.Trace().Msg("Tentando pegar as informações do usuário...") |
| 87 | + username, err := pgo.GetUserName(usrtoken) |
| 88 | + if err != nil { |
| 89 | + llgg.Error().Str("Erro", err.Error()).Msg("Problema ao obter o nome do usuário!") |
| 90 | + } |
| 91 | + //Corta o nome do usuário, mostrando apenas o primeiro nome |
| 92 | + username = strings.Split(username, " ")[0] |
| 93 | + llgg.Trace().Str("Nome do usuário", username).Msg("Nome obtido com sucesso!") |
106 | 94 |
|
107 |
| -} |
| 95 | + _, userid, _, err := pgo.GetUserInfo(usrtoken) |
| 96 | + if err != nil { |
| 97 | + llgg.Error().Str("Erro", err.Error()).Msg("Problema ao obter o ID do usuário!") |
| 98 | + ui.MsgBoxError(mainwin, "Não foi possível obter sua turma.", "Por favor verifique a sua conexão com a internet.") |
| 99 | + os.Exit(0) |
| 100 | + } |
108 | 101 |
|
109 |
| -func postReq(url string, method string, payload string) (string, error) { |
| 102 | + ensino, nivel, sala, err := GetClass(usrtoken, userid) |
110 | 103 |
|
111 |
| - client := &http.Client{} |
112 |
| - fmt.Println("[d | postReq] Payload:", payload) |
113 |
| - req, err := http.NewRequest(method, url, strings.NewReader(payload)) |
| 104 | + if err != nil { |
| 105 | + llgg.Error().Str("Erro", err.Error()).Msg("Problema ao obter o ID do usuário!") |
| 106 | + ui.MsgBoxError(mainwin, "Não foi possível obter sua turma.", "Por favor verifique a sua conexão com a internet.") |
| 107 | + os.Exit(0) |
| 108 | + } |
114 | 109 |
|
115 |
| - if err != nil { |
116 |
| - fmt.Println("[e | postReq]", err) |
117 |
| - return "Failed to create request:", err |
118 |
| - } |
119 |
| - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") |
| 110 | + ui.MsgBox(mainwin, "Parabéns, "+username, "Você é do "+ensino+", está na "+nivel+" e é da sala "+trimLeftChars(sala, 2)) |
120 | 111 |
|
121 |
| - res, err := client.Do(req) |
122 |
| - if err != nil { |
123 |
| - fmt.Println("[e | postReq]", err) |
124 |
| - return "Failed to send request: ", err |
125 |
| - } |
126 |
| - defer res.Body.Close() |
| 112 | + //Vai para a página apos o login |
| 113 | + mainwin.Destroy() |
127 | 114 |
|
128 |
| - body, err := ioutil.ReadAll(res.Body) |
| 115 | + ui.Quit() |
| 116 | + |
| 117 | + }) |
| 118 | + aboutform.Append("", loginButton, false) |
| 119 | + |
| 120 | + return vbox |
| 121 | +} |
| 122 | + |
| 123 | +func setupUI() { |
| 124 | + mainwin = ui.NewWindow("Turma Finder", 640, 480, true) |
| 125 | + mainwin.OnClosing(func(*ui.Window) bool { |
| 126 | + ui.Quit() |
| 127 | + return true |
| 128 | + }) |
| 129 | + ui.OnShouldQuit(func() bool { |
| 130 | + mainwin.Destroy() |
| 131 | + return true |
| 132 | + }) |
| 133 | + |
| 134 | + tab := ui.NewTab() |
| 135 | + mainwin.SetChild(tab) |
| 136 | + mainwin.SetMargined(true) |
| 137 | + |
| 138 | + tab.Append("Inicio", loginPage()) |
| 139 | + tab.SetMargined(0, true) |
| 140 | + |
| 141 | + mainwin.Show() |
| 142 | +} |
| 143 | + |
| 144 | +func main() { |
| 145 | + ui.Main(setupUI) |
| 146 | +} |
| 147 | + |
| 148 | +func GetClass(token string, userId string) (string, string, string, error) { |
| 149 | + getclassresponse, err := tokenRequest("https://apihub.positivoon.com.br/api/NivelEnsino?usuarioId="+userId, "GET", token) |
129 | 150 | if err != nil {
|
130 |
| - fmt.Println("[e | postReq]", err) |
131 |
| - return "Failed to read response: ", err |
| 151 | + return "", "", "", err |
132 | 152 | }
|
| 153 | + //unmarshal response |
| 154 | + var userclass UserClass |
| 155 | + json.Unmarshal([]byte(getclassresponse), &userclass) |
| 156 | + return userclass[0].Label, userclass[0].Turmas[0].NomeSerie, userclass[0].Turmas[0].NomeTurma, nil |
133 | 157 |
|
134 |
| - //fmt.Println("[d] Response:", string(body)) |
135 |
| - //Check if response is valid |
136 |
| - if res.StatusCode != 200 { |
137 |
| - //Unmarshal error response |
138 |
| - var errResp Error |
139 |
| - json.Unmarshal(body, &errResp) |
140 |
| - fmt.Println("[e | postReq] Error:", errResp.Error) |
141 |
| - fmt.Println("[e | postReq] Error description:", errResp.ErrorDescription) |
142 |
| - zenity.Error(errResp.ErrorDescription, zenity.Title("Erro"), zenity.ErrorIcon) |
143 |
| - return errResp.Error + ": " + errResp.ErrorDescription, err |
144 |
| - } |
145 |
| - //Unmarshal response |
146 |
| - var token Token |
147 |
| - json.Unmarshal(body, &token) |
148 |
| - //convert int to string |
149 |
| - expiresIn := fmt.Sprintf("%d", token.ExpiresIn) |
150 |
| - fmt.Println("[d | postReq] Token: "+token.AccessToken, "\n[d | postReq] Refresh Token: "+token.RefreshToken, "\n[d | postReq] Expires In: "+expiresIn, "\n[d | postReq] Token Type: "+token.TokenType) |
151 |
| - //zenity.Info("Login realizado com sucesso!\n\nIremos agora tentar carregar as soluções...", zenity.Title("Login realizado com sucesso!"), zenity.InfoIcon) |
152 |
| - return token.AccessToken, nil |
153 | 158 | }
|
154 | 159 |
|
155 |
| -func authReq(url string, method string, token string) (string, error) { |
156 |
| - |
| 160 | +func tokenRequest(url string, method string, token string) (string, error) { |
157 | 161 | client := &http.Client{}
|
| 162 | + |
158 | 163 | req, err := http.NewRequest(method, url, nil)
|
159 | 164 |
|
160 | 165 | if err != nil {
|
161 |
| - return "", err |
| 166 | + return "", errors.New("Não foi possível criar a requesição:" + err.Error()) |
162 | 167 | }
|
| 168 | + |
| 169 | + req.Header.Add("Content-Type", "application/json") |
163 | 170 | req.Header.Add("Authorization", "Bearer "+token)
|
164 | 171 |
|
165 | 172 | res, err := client.Do(req)
|
| 173 | + |
166 | 174 | if err != nil {
|
167 |
| - fmt.Println("[e | authReq]", err) |
168 |
| - return "", err |
| 175 | + return "", errors.New("Não foi possível enviar a requisão:" + err.Error()) |
169 | 176 | }
|
| 177 | + |
170 | 178 | defer res.Body.Close()
|
171 | 179 |
|
172 | 180 | body, err := ioutil.ReadAll(res.Body)
|
173 | 181 | if err != nil {
|
174 |
| - fmt.Println("[e | authReq]", err) |
175 |
| - return "", err |
| 182 | + return "", errors.New("Não foi possível ler a resposta:" + err.Error()) |
176 | 183 | }
|
| 184 | + |
177 | 185 | return string(body), nil
|
178 | 186 | }
|
| 187 | + |
| 188 | +func trimLeftChars(s string, n int) string { |
| 189 | + //See https://stackoverflow.com/a/48798875 |
| 190 | + m := 0 |
| 191 | + for i := range s { |
| 192 | + if m >= n { |
| 193 | + return s[i:] |
| 194 | + } |
| 195 | + m++ |
| 196 | + } |
| 197 | + return s[:0] |
| 198 | +} |
0 commit comments