data.go 7.93 KB
package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/olivere/elastic/v7"

	_ "github.com/mattn/go-sqlite3"
)

type Call struct {
	ID       int       `json:"id" db:"id"`
	Type     int       `json:"type" db:"type"`
	Name     *string   `json:"name" db:"name"`
	Number   int       `json:"number" db:"number"`
	Duration int       `json:"duration" db:"duration"`
	Date     time.Time `json:"date" db:"date"`
}

func (app *App) GetCalls(c echo.Context) error {
	calls := []Call{}

	query := `SELECT * FROM calls WHERE extraction_no=?`
	app.db.Unsafe().Select(&calls, query, c.Param("no"))

	return c.JSON(http.StatusOK, calls)
}

func (app *App) PostCall(c echo.Context) error {
	call := Call{}
	if err := c.Bind(&call); err != nil {
		return err
	}

	query := "INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?)"
	_, err := app.db.Exec(query, c.Param("no"), call.ID, call.Type, call.Name, call.Number, call.Duration, call.Date)
	if err != nil {
		return nil
	}

	return c.NoContent(http.StatusNoContent)
}

func (app *App) DeleteCall(c echo.Context) error {
	query := "DELETE FROM calls WHERE `extraction_no`=? AND `id`=?"
	res, err := app.db.Exec(query, c.Param("no"), c.Param("id"))
	if err != nil {
		return err
	}

	if rows, err := res.RowsAffected(); err != nil {
		return err
	} else if rows == 0 {
		return echo.NewHTTPError(http.StatusNotFound, "Can not find the call")
	} else {
		return c.NoContent(http.StatusNoContent)
	}
}

type CallStats struct {
	Number   string  `json:"number" db:"number"`
	Name     *string `json:"name" db:"name"`
	Incoming int     `json:"incoming" db:"incoming"`
	Outgoing int     `json:"outgoing" db:"outgoing"`
	Duration int     `json:"duration" db:"duration"`
}

func (app *App) GetCallsAnalyses(c echo.Context) error {
	calls := []CallStats{}

	query := `SELECT number, name,
		(SELECT COUNT(1) FROM calls s WHERE s.extraction_no=c.extraction_no AND s.number=c.number AND s.type=1) incoming,
		(SELECT COUNT(1) FROM calls s WHERE s.extraction_no=c.extraction_no AND s.number=c.number AND s.type=2) outgoing,
		SUM(duration) duration
	FROM calls c WHERE extraction_no=? GROUP BY number ORDER BY duration DESC`
	app.db.Select(&calls, query, c.Param("no"))

	return c.JSON(http.StatusOK, calls)
}

type AppInfo struct {
	PackageName    string    `json:"package_name" db:"package_name"`
	Name           string    `json:"name" db:"name"`
	Version        string    `json:"version" db:"version"`
	WifiUsage      int       `json:"wifi_usage" db:"wifi_usage"`
	CellularUsage  int       `json:"cellular_usage" db:"cellular_usage"`
	LastUsed       time.Time `json:"last_used" db:"last_used"`
	ForegroundTime int64     `json:"foreground_time" db:"foreground_time"`
}

func (app *App) GetAppsAnalyses(c echo.Context) error {
	apps := []AppInfo{}

	query := `SELECT * FROM apps WHERE extraction_no=? ORDER BY foreground_time DESC LIMIT 0, 100`
	app.db.Unsafe().Select(&apps, query, c.Param("no"))

	return c.JSON(http.StatusOK, apps)
}

func (app *App) PostAppAnalysis(c echo.Context) error {
	info := AppInfo{}
	if err := c.Bind(&info); err != nil {
		return err
	}

	query := "INSERT INTO apps VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
	_, err := app.db.Exec(
		query,
		c.Param("no"), info.PackageName, info.Name, info.Version,
		info.WifiUsage, info.CellularUsage, info.LastUsed, info.ForegroundTime,
	)
	if err != nil {
		return err
	}

	return c.NoContent(http.StatusNoContent)
}

func (app *App) DeleteAppAnalysis(c echo.Context) error {
	query := "DELETE FROM apps WHERE `extraction_no`=? AND `package_name`=?"
	res, err := app.db.Exec(query, c.Param("no"), c.Param("package"))
	if err != nil {
		return err
	}

	if rows, err := res.RowsAffected(); err != nil {
		return err
	} else if rows == 0 {
		return echo.NewHTTPError(http.StatusNotFound, "Can not find the app")
	} else {
		return c.NoContent(http.StatusNoContent)
	}
}

type Message struct {
	ID      int       `json:"id" db:"id"`
	Type    int       `json:"type" db:"type"`
	Address string    `json:"address" db:"address"`
	Body    string    `json:"body" db:"body"`
	Date    time.Time `json:"date" db:"date"`
}

func (app *App) GetMessages(c echo.Context) error {
	messages := []Message{}

	no := c.Param("no")

	q := c.QueryParam("q")
	if len(q) > 0 {
		res, err := app.es.Search("messages-" + no).
			Query(elastic.NewMatchQuery("content", q)).
			Do(context.Background())

		if err != nil {
			return err
		}

		for _, hit := range res.Hits.Hits {
			message := Message{}

			app.db.Unsafe().Get(
				&message,
				"SELECT * FROM messages WHERE extraction_no=? AND `id`=?",
				no, hit.Id,
			)

			messages = append(messages, message)
		}
	} else {
		app.db.Unsafe().Select(&messages, `SELECT * FROM messages WHERE extraction_no=?`, no)
	}

	return c.JSON(http.StatusOK, messages)
}

func (app *App) PostMessage(c echo.Context) error {
	message := Message{}
	if err := c.Bind(&message); err != nil {
		return err
	}

	query := "INSERT INTO messages VALUES (?, ?, ?, ?, ?, ?)"
	_, err := app.db.Exec(query, c.Param("no"), message.ID, message.Type, message.Address, message.Body, message.Date)

	if err != nil {
		return err
	}

	return c.NoContent(http.StatusNoContent)
}

func (app *App) DeleteMessage(c echo.Context) error {
	query := "DELETE FROM messages WHERE `extraction_no`=? AND `id`=?"
	res, err := app.db.Exec(query, c.Param("no"), c.Param("id"))
	if err != nil {
		return err
	}

	if rows, err := res.RowsAffected(); err != nil {
		return err
	} else if rows == 0 {
		return echo.NewHTTPError(http.StatusNotFound, "Can not find the message")
	} else {
		return c.NoContent(http.StatusNoContent)
	}
}

type MessageStats struct {
	Address string `json:"address" db:"address"`
	Receive int    `json:"receive" db:"receive"`
	Send    int    `json:"send" db:"send"`
}

func (app *App) GetMessagesAnalyses(c echo.Context) error {
	messages := []MessageStats{}

	query := `SELECT address,
		(SELECT COUNT(1) FROM messages m WHERE m.extraction_no=s.extraction_no AND m.address=s.address AND m.type=1) receive,
		(SELECT COUNT(1) FROM messages m WHERE m.extraction_no=s.extraction_no AND m.address=s.address AND m.type=2) send
	FROM messages s WHERE extraction_no=? GROUP BY address ORDER BY receive + send DESC`
	app.db.Select(&messages, query, c.Param("no"))

	return c.JSON(http.StatusOK, messages)
}

type Process struct {
	PID   int    `json:"pid" db:"pid"`
	UID   string `json:"uid" db:"uid"`
	PPID  int    `json:"ppid" db:"ppid"`
	STime string `json:"stime" db:"stime"`
	Time  string `json:"time" db:"time"`
	CMD   string `json:"cmd" db:"cmd"`
}

func (app *App) GetProcesses(c echo.Context) error {
	processes := []Process{}

	query := "SELECT * FROM processes WHERE `extraction_no`=? AND `uid` LIKE 'u%' ORDER BY `time` DESC"
	fmt.Println(app.db.Unsafe().Select(&processes, query, c.Param("no")))

	return c.JSON(http.StatusOK, processes)
}

type Alarm struct {
	ID      string         `json:"id" db:"id"`
	When    time.Time      `json:"when" db:"when"`
	History []AlarmHistory `json:"history" db:"-"`
}

type AlarmHistory struct {
	Type string    `json:"type" db:"type"`
	When time.Time `json:"when" db:"when"`
}

func (app *App) GetAlarms(c echo.Context) error {
	alarms := []Alarm{}
	query := "SELECT * FROM alarms WHERE `extraction_no`=?"

	extNo := c.Param("no")
	if err := app.db.Unsafe().Select(&alarms, query, extNo); err != nil {
		return err
	}

	query = "SELECT * FROM alarm_histories WHERE `extraction_no`=? AND `id`=?"
	for i := range alarms {
		if err := app.db.Unsafe().Select(&alarms[i].History, query, extNo, alarms[i].ID); err != nil {
			return err
		}
	}

	return c.JSON(http.StatusOK, alarms)
}

type Schedule struct {
	ID    int       `json:"id" db:"id"`
	Name  string    `json:"name" db:"name"`
	Begin time.Time `json:"begin" db:"begin"`
	End   time.Time `json:"end" db:"end"`
}

func (app *App) GetSchedules(c echo.Context) error {
	schedules := []Schedule{}
	query := "SELECT * FROM schedules WHERE `extraction_no`=?"
	if err := app.db.Unsafe().Select(&schedules, query, c.Param("no")); err != nil {
		return err
	}

	return c.JSON(http.StatusOK, schedules)
}