· last year · Feb 07, 2024, 08:45 AM
1package cronjobs
2
3import (
4 "fmt"
5 "github.com/bwmarrin/discordgo"
6 "github.com/go-zoox/fetch"
7 "github.com/gopxl/beep"
8 "github.com/gopxl/beep/mp3"
9 "github.com/gopxl/beep/speaker"
10 "github.com/lactobasilusprotectus/go-discord/internal/sporact"
11 "github.com/lactobasilusprotectus/go-discord/internal/util/JsonParser"
12 config2 "github.com/lactobasilusprotectus/go-discord/pkg/config"
13 "log"
14 "net/url"
15 "os"
16 "time"
17)
18
19var (
20 //Mendefinisikan mapping antara ID tenant dengan nama mereka. Ini digunakan untuk mengidentifikasi tenant dalam notifikasi.
21 mapTenatID = map[int]string{
22 6: "Kementerian Komunikasi dan Informatika",
23 10: "Mandiri Investasi",
24 5: "Mandiri Sekuritas",
25 17: "Pelindo",
26 20: "PT Samuel Sekuritas Indonesia",
27 21: "PT Bukit Asam",
28 22: "ASDP Indonesia Ferry",
29 }
30
31 //ctx = context.Background()
32)
33
34// GetAlertSporact Struct yang digunakan untuk mengatur sesi Discord, informasi klien API untuk mengambil peringatan, dan beberapa konfigurasi lainnya.
35type GetAlertSporact struct {
36 Session *discordgo.Session
37 ChannelID string
38 Scheduler string
39 AccessToken string
40 RefreshToken string
41 LastAccessID int
42 Client *sporact.Client
43}
44
45// Response Struct untuk menampung respons dari API peringatan, termasuk detail kasus seperti ID, judul, deskripsi, dan lainnya.
46type Response struct {
47 Id int `json:"id"`
48 CaseID string `json:"case_id"`
49 Title string `json:"title"`
50 Description string `json:"description"`
51 Status string `json:"status"`
52 Priority string `json:"priority"`
53 Impact string `json:"impact"`
54 Tenant string `json:"tenant"`
55}
56
57// initJsonManager Menginisialisasi manajer JSON untuk membaca dan menulis konfigurasi.
58func (job *GetAlertSporact) initJsonManager() *JsonParser.JSONManager {
59 //get file config.json
60 getwd, err := os.Getwd()
61
62 if err != nil {
63 return nil
64 }
65
66 return JsonParser.NewJSONManager(getwd + "/config.json")
67}
68
69// NewGetAlertSporact Membuat instance GetAlertSporact baru dengan menginisialisasi sesi Discord, ID channel, scheduler, token akses, dan klien API berdasarkan konfigurasi yang dibaca dari config.json.
70func NewGetAlertSporact(session *discordgo.Session, channelID string, scheduler string) *GetAlertSporact {
71 var config config2.Config
72
73 //init json manager
74 manager := new(GetAlertSporact).initJsonManager()
75
76 //read config.json
77 jsonConfig, err := manager.Read(config)
78 if err != nil {
79 log.Printf("line 67 error: %v", err)
80 return nil
81 }
82
83 //return jsonConfig map[access_key: last_case_id:0 refresh_key:]
84 mapConfig, ok := jsonConfig.(map[string]interface{})
85 if !ok {
86 log.Printf("line 74 error: %v", err)
87 return nil
88 }
89
90 //get access key
91 accessKeyValue, ok := mapConfig["access_key"].(string)
92 if !ok {
93 log.Printf("error: %v", err)
94 return nil
95 }
96
97 //get refresh key
98 refreshKeyValue, ok := mapConfig["refresh_key"].(string)
99 if !ok {
100 log.Printf("error: %v", err)
101 return nil
102 }
103
104 //get last case id
105 lastCaseIDValue, ok := mapConfig["last_case_id"].(float64)
106
107 //set config
108 config.AccessKey = accessKeyValue
109 config.RefreshKey = refreshKeyValue
110 config.LastCaseID = int(lastCaseIDValue)
111
112 //new http sporact
113 client := sporact.NewClient(config.AccessKey)
114
115 //return GetAlertSporact
116 return &GetAlertSporact{
117 Session: session,
118 ChannelID: channelID,
119 Scheduler: scheduler,
120 AccessToken: config.AccessKey,
121 RefreshToken: config.RefreshKey,
122 Client: client,
123 LastAccessID: config.LastCaseID,
124 }
125}
126
127// Schedule mendefinisikan waktu berjalannya cron job
128func (job *GetAlertSporact) Schedule() string {
129 return job.Scheduler
130}
131
132// Task adalah fungsi yang akan dijalankan oleh cron job. Fungsi ini akan memproses data dari API peringatan, mengirim notifikasi ke Discord, dan memainkan alarm jika ada kasus baru yang masuk.
133func (job *GetAlertSporact) Task() {
134 data, err := job.ProcessData()
135
136 if err != nil {
137 log.Printf("line 119 error: %v", err)
138 return
139 }
140
141 if data.Id == job.LastAccessID {
142 log.Printf("cron job success")
143 return
144 }
145
146 title := fmt.Sprintf("🚨 **Aktivitas Mencurigakan Terdeteksi** 🚨\n\n")
147 title += fmt.Sprintf("Case ID: %s - %s\n", data.CaseID, data.Tenant)
148 title += fmt.Sprintf("Workbench: %s\n", data.Title)
149
150 if err != nil {
151 log.Printf("line 141 error: %v", err)
152 return
153 }
154
155 embeb := &discordgo.MessageEmbed{
156 Title: title,
157 Description: fmt.Sprintf("Ini merupakan notifikasi untuk case baru yang masuk ke sporact"),
158 Fields: []*discordgo.MessageEmbedField{
159
160 {
161 Name: "Status",
162 Value: data.Status,
163 Inline: false,
164 },
165
166 {
167 Name: "Prioritas",
168 Value: fmt.Sprintf("%s - %s", data.Priority, data.Impact),
169 Inline: false,
170 },
171
172 {
173 Name: "Link",
174 Value: fmt.Sprintf("https://sporact.mii.co.id/cases/%s", data.CaseID),
175 },
176 },
177 Color: getColorByPriority(data.Impact),
178 }
179
180 _, err = job.Session.ChannelMessageSendComplex(job.ChannelID, &discordgo.MessageSend{
181 Embed: embeb,
182 })
183
184 if err != nil {
185 log.Printf("line 178 error: %v", err)
186 }
187
188 job.LastAccessID = data.Id
189
190 //write config.json
191 err = job.WriteJson(data)
192
193 if err != nil {
194 log.Printf(err.Error())
195 return
196 }
197
198 log.Printf("cron job success")
199
200 err = job.PlayAlarm()
201 if err != nil {
202 log.Printf("line 186 error: %v", err)
203 return
204 }
205
206 return
207}
208
209// PlayAlarm memainkan alarm jika ada kasus baru yang masuk.
210func (job *GetAlertSporact) PlayAlarm() (err error) {
211 //get file config.json
212 getwd, err := os.Getwd()
213
214 if err != nil {
215 return err
216 }
217
218 f, err := os.Open(getwd + "/etc/1.mp3")
219
220 if err != nil {
221 return err
222 }
223
224 streamer, format, err := mp3.Decode(f)
225
226 if err != nil {
227 return err
228 }
229
230 defer streamer.Close()
231
232 speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
233
234 done := make(chan bool)
235 speaker.Play(beep.Seq(streamer, beep.Callback(func() {
236 done <- true
237 })))
238
239 <-done
240
241 return err
242}
243
244// ProcessData memproses data dari API Sporact.
245func (job *GetAlertSporact) ProcessData() (Response, error) {
246 res, err := job.GetAlertCaseApi()
247
248 if err != nil {
249 return Response{}, fmt.Errorf("error: %v", err)
250 }
251
252 mapData := res.Get("results.0")
253
254 respStruct := Response{
255 Id: int(mapData.Get("id").Int()),
256 CaseID: mapData.Get("uid").String(),
257 Title: mapData.Get("title").String(),
258 Description: mapData.Get("description").String(),
259 Status: mapData.Get("status_display").String(),
260 Priority: mapData.Get("priority.name").String(),
261 Impact: mapData.Get("impact_details.name").String(),
262 Tenant: mapTenatID[int(mapData.Get("tenant_id").Int())],
263 }
264
265 return respStruct, nil
266}
267
268// GetAlertCaseApi gets the alert case from Sporact MII API.
269func (job *GetAlertSporact) GetAlertCaseApi() (*fetch.Response, error) {
270 // Get current time and yesterday
271 now := time.Now()
272 yesterday := now.Add(-24 * time.Hour)
273
274 // Formatting the times in the required format
275 nowFormatted := now.Format("2006-01-02T15:04:05.000Z")
276 yesterdayFormatted := yesterday.Format("2006-01-02T15:04:05.000Z")
277
278 //construct url
279 // Base URL
280 baseURL := "/cases/case/"
281
282 // Parameters
283 params := url.Values{}
284 params.Add("date[]", yesterdayFormatted)
285 params.Add("date[]", nowFormatted)
286 params.Add("range_type", "created___range")
287 params.Add("status", "Open")
288 params.Add("tenant", "6,10,5,17,20,21,22")
289 params.Add("expand", "priority")
290
291 // Constructing the URL
292 fullURL := baseURL + "?" + params.Encode()
293
294 res, err := job.Client.MakeGetRequest(fullURL)
295
296 if err != nil {
297 return nil, fmt.Errorf("error: %v", err)
298 }
299
300 if res.StatusCode() == 401 {
301 err = job.refreshToken()
302 if err != nil {
303 return nil, fmt.Errorf("error: %v", err)
304 }
305
306 job.Client = sporact.NewClient(job.AccessToken)
307
308 log.Printf("refresh token success")
309
310 return job.GetAlertCaseApi()
311 }
312
313 if res.StatusCode() != 200 {
314 return nil, fmt.Errorf("http status code: %d message: %s", res.StatusCode(), res.Get("message").String())
315 }
316
317 return res, nil
318}
319
320// refreshToken refreshes the access token if expired.
321func (job *GetAlertSporact) refreshToken() error {
322 body := map[string]interface{}{
323 "refresh": job.RefreshToken,
324 }
325
326 resp, err := job.Client.MakePostRequest("/auth/token/refresh/", body)
327
328 if err != nil {
329 return fmt.Errorf("error: %v", err)
330 }
331
332 if resp.StatusCode() != 200 {
333 return fmt.Errorf("http status code: %d message: %s", resp.StatusCode(), resp.Get("message").String())
334 }
335
336 //set new access token
337 job.AccessToken = resp.Get("access").String()
338
339 return nil
340}
341
342// WriteJson writes the response to the config.json file.
343func (job *GetAlertSporact) WriteJson(response Response) error {
344 jsonManager := job.initJsonManager()
345
346 config := config2.Config{
347 AccessKey: job.AccessToken,
348 RefreshKey: job.RefreshToken,
349 LastCaseID: response.Id,
350 }
351
352 //write config.json
353 return jsonManager.Write(config)
354}
355
356// getColorByPriority returns the color code based on the priority.
357func getColorByPriority(priority string) int {
358 switch priority {
359 case "High":
360 return 0xFF0000 // Merah
361 case "Medium":
362 return 0xFFFF00 // Kuning
363 case "Low":
364 return 0x00FF00 // Hijau
365 default:
366 return 0x808080 // Abu-abu untuk prioritas tidak dikenal
367 }
368}
369