Fix wrong positional parameters.

Add handler for InstalledApplicationList request type.
installed applications are inserted but their relationship to the current device is not yet recorded. work in progress.
This commit is contained in:
Mosen
2016-07-17 23:09:15 +10:00
parent 66ec74ce78
commit e90c78da17
2 changed files with 100 additions and 35 deletions

View File

@@ -66,13 +66,13 @@ func (store pgStore) New(a *Application) (string, error) {
dynamic_size,
is_validated
)
VALUES ($0, $1, $2, $3, $4, $5, $6)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (name, version) DO UPDATE SET
identifier=$1,
short_version=$2,
bundle_size=$4,
dynamic_size=$5,
is_validated=$6
identifier=$2,
short_version=$3,
bundle_size=$5,
dynamic_size=$6,
is_validated=$7
RETURNING application_uuid;`,
a.Name,
a.Identifier,
@@ -92,7 +92,16 @@ func (store pgStore) New(a *Application) (string, error) {
// Retrieve a list of applications
func (store pgStore) Applications(params ...interface{}) ([]Application, error) {
stmt := `SELECT * FROM applications`
stmt := `SELECT
application_uuid,
name,
identifier,
short_version,
version,
bundle_size,
dynamic_size,
is_validated
FROM applications`
stmt = addWhereFilters(stmt, "OR", params...)
var apps []Application
@@ -106,13 +115,25 @@ func (store pgStore) Applications(params ...interface{}) ([]Application, error)
// Retrieve only applications which are installed on the given device.
func (store pgStore) GetApplicationsByDeviceUUID(deviceUUID string) ([]Application, error) {
if len(deviceUUID) == 0 {
return nil, errors.New("empty uuid supplied to GetApplicationsByDeviceUUID")
}
var apps []Application
query := `SELECT * FROM applications
query := `SELECT
applications.application_uuid AS application_uuid,
name,
identifier,
short_version,
version,
bundle_size,
dynamic_size,
is_validated
FROM applications
RIGHT JOIN devices_applications ON applications.application_uuid = devices_applications.application_uuid
WHERE devices_applications.device_uuid=$1`
err := store.Select(&apps, query, deviceUUID)
if err != nil {
return nil, err
}
@@ -122,6 +143,14 @@ func (store pgStore) GetApplicationsByDeviceUUID(deviceUUID string) ([]Applicati
// Associate the given applications with the given device uuid by inserting into `device_applications`.
func (store pgStore) SaveApplicationByDeviceUUID(deviceUUID string, app *Application) error {
if deviceUUID == "" {
return errors.New("empty uuid supplied to SaveApplicationByDeviceUUID for deviceUUID")
}
if app.UUID == "" {
return errors.New("empty uuid supplied to SaveApplicationByDeviceUUID for application")
}
stmt := `INSERT INTO devices_applications (
device_uuid, application_uuid
) VALUES ($1, $2)`

View File

@@ -41,6 +41,11 @@ func (svc service) Acknowledge(ctx context.Context, req mdm.Response) (int, erro
if err := svc.ackQueryResponses(req); err != nil {
return 0, err
}
case "InstalledApplicationList":
if err := svc.ackInstalledApplicationList(req); err != nil {
fmt.Printf("Got an error acknowledging InstalledApplicationList: %v\n", err)
return 0, err
}
default:
// Need to handle the absence of RequestType in IOS8 devices
if req.QueryResponses.UDID != "" {
@@ -137,62 +142,93 @@ func (svc service) ackQueryResponses(req mdm.Response) error {
// Acknowledge a response to `InstalledApplicationList`.
func (svc service) ackInstalledApplicationList(req mdm.Response) error {
device, err := svc.devices.GetDeviceByUDID(req.UDID)
fmt.Println("Acknowledging installed applications")
device, err := svc.devices.GetDeviceByUDID(req.UDID, "device_uuid")
if err != nil {
return err
return errors.Wrap(err, "getting a device record by udid")
}
requestApps := make([]apps.Application, len(req.InstalledApplicationList))
// Update or insert application records that do not exist, returning the UUID so that it can be inserted for
// the device sending the response.
for _, reqApp := range req.InstalledApplicationList {
identifier := sql.NullString{reqApp.Identifier, reqApp.Identifier != ""}
shortVersion := sql.NullString{reqApp.ShortVersion, reqApp.ShortVersion != ""}
version := sql.NullString{reqApp.Version, reqApp.Version != ""}
bundleSize := sql.NullInt64{}
bundleSize.Scan(reqApp.BundleSize)
dynamicSize := sql.NullInt64{}
dynamicSize.Scan(reqApp.DynamicSize)
newApp := apps.Application{
Name: reqApp.Name,
Identifier: identifier,
ShortVersion: shortVersion,
Version: version,
BundleSize: bundleSize,
DynamicSize: dynamicSize,
}
appUuid, err := svc.apps.New(&newApp)
if err != nil {
return err
}
newApp.UUID = appUuid
requestApps = append(requestApps, newApp)
}
deviceApps, err := svc.apps.GetApplicationsByDeviceUUID(device.UUID)
if err != nil {
return err
return errors.Wrap(err, "getting applications by device uuid")
}
var removed []apps.Application = make([]apps.Application, len(req.InstalledApplicationList))
var deviceAppsRemaining []apps.Application = make([]apps.Application, len(req.InstalledApplicationList))
var deviceRemoved []apps.Application = make([]apps.Application, len(req.InstalledApplicationList))
var deviceNotRemoved []apps.Application = make([]apps.Application, len(req.InstalledApplicationList))
// Check to see whether installed applications exist in the latest response
// If they do not, they are added to the removed slice.
// TODO: This is a pretty horrible algorithm and I should re-design it at some point. m.
fmt.Println("Determining apps removed")
removedouter:
for _, deviceApp := range deviceApps {
for _, app := range req.InstalledApplicationList {
if deviceApp.Version.Valid && deviceApp.Version.String == app.Version && deviceApp.Name == app.Name {
deviceAppsRemaining = append(deviceAppsRemaining, deviceApp)
for _, app := range requestApps {
if deviceApp.Version == app.Version && deviceApp.Name == app.Name {
deviceNotRemoved = append(deviceNotRemoved, deviceApp)
continue removedouter
}
}
removed = append(removed, deviceApp)
deviceRemoved = append(deviceRemoved, deviceApp)
}
// Any installed applications that are already represented in the `applications` table AND
// allocated to the device in `devices_applications` should be skipped.
var updated []apps.Application = make([]apps.Application, len(req.InstalledApplicationList))
fmt.Println("Determining apps changed or added")
skip:
for _, ackApp := range req.InstalledApplicationList {
for _, app := range deviceAppsRemaining {
if app.Name == ackApp.Name && app.Version.Valid && app.Version.String == ackApp.Version {
for _, ackApp := range requestApps {
for _, app := range deviceNotRemoved {
if app.Name == ackApp.Name && app.Version == ackApp.Version {
continue skip
}
}
identifier := sql.NullString{ackApp.Identifier, ackApp.Identifier != ""}
appUpdated := apps.Application{
Name: ackApp.Name,
Identifier: identifier,
//ShortVersion: sql.NullString{}.Scan(ackApp.ShortVersion),
//Version: sql.NullString{}.Scan(ackApp.Version),
//BundleSize: sql.NullInt64{}.Scan(ackApp.BundleSize),
//DynamicSize: sql.NullInt64{}.Scan(ackApp.DynamicSize),
//IsValidated: sql.NullBool{}.Scan(ackApp.IsValidated),
}
updated = append(updated, appUpdated)
updated = append(updated, ackApp)
}
fmt.Printf("removed %#v\n", removed)
fmt.Printf("updated %#v\n", updated)
fmt.Printf("removed %d application(s)\n", len(deviceRemoved))
fmt.Printf("updated %d application(s)\n", len(updated))
for _, insertApp := range updated {
if err := svc.apps.SaveApplicationByDeviceUUID(device.UUID, &insertApp); err != nil {
fmt.Printf("could not save application, no valid uuid: %s\n", insertApp.Name)
// return errors.Wrap(err, "saving installed application for a device")
}
}
return nil
}