<commit_before>/*
 * Copyright (c) 2015 ZionSoft. All rights reserved.
 * Use of this source code is governed by a BSD-style license
 * that can be found in the LICENSE file.
 */

package account

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"appengine"
	"appengine/datastore"

	"src/core"
)

func registerDeviceAccountHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		panic(&core.Error{http.StatusMethodNotAllowed, ""})
	}

	var da deviceAccount
	if err := da.unmarshalHTTPRequest(r); err != nil {
		panic(&core.Error{http.StatusBadRequest, ""})
	}

	c := appengine.NewContext(r)
	err := datastore.RunInTransaction(c, func(c appengine.Context) error {
		if da.AccountID == 0 {
			// it might be a new device, or the request is fired by old clients
			if existing, ok := daCache.Get(da.PushNotificationID); ok {
				// hit in-memory cache, so it's a known device with old client
				da.AccountID = existing.(deviceAccount).AccountID
				da.Created = existing.(deviceAccount).Created
			} else {
				// missed in-memory cache, should fall back to datastore
				q := datastore.NewQuery("DeviceAccount").
					Ancestor(createDeviceAccountAncestorKey(c)).
					Filter("PushNotificationID =", da.PushNotificationID)
				count, err := q.Count(c)
				if err != nil {
					return err
				}

				if count == 0 {
					// from an unknown device, should create a new account
					key, err := datastore.Put(c, createIncompleteDeviceAccountKey(c), &da)
					if err != nil {
						return err
					}
					da.AccountID = key.IntID()
					daCache.Set(da.PushNotificationID, da)
					return nil
				} else {
					var existing []*deviceAccount
					keys, err := q.GetAll(c, &existing)
					if err != nil {
						return err
					}
					da.AccountID = keys[0].IntID()
					da.Created = existing[0].Created
				}
			}

			_, err := datastore.Put(c, createDeviceAccountKey(c, da.AccountID), &da)
			daCache.Set(da.PushNotificationID, da)
			return err
		} else {
			// update existing account (for request fired by new clients)
			key := strconv.FormatInt(da.AccountID, 10)
			if existing, ok := daCache.Get(key); ok {
				// hit in-memory cache
				da.Created = existing.(deviceAccount).Created
			} else {
				// missed in-memory cache, falls back to datastore
				var existing deviceAccount
				if err := datastore.Get(c, createDeviceAccountKey(c, da.AccountID), &existing); err != nil {
					return err
				}
				da.Created = existing.Created
			}<commit_msg>Removed one unnecessary query.<commit_after>/*
 * Copyright (c) 2015 ZionSoft. All rights reserved.
 * Use of this source code is governed by a BSD-style license
 * that can be found in the LICENSE file.
 */

package account

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"appengine"
	"appengine/datastore"

	"src/core"
)

func registerDeviceAccountHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		panic(&core.Error{http.StatusMethodNotAllowed, ""})
	}

	var da deviceAccount
	if err := da.unmarshalHTTPRequest(r); err != nil {
		panic(&core.Error{http.StatusBadRequest, ""})
	}

	c := appengine.NewContext(r)
	err := datastore.RunInTransaction(c, func(c appengine.Context) error {
		if da.AccountID == 0 {
			// it might be a new device, or the request is fired by old clients
			if existing, ok := daCache.Get(da.PushNotificationID); ok {
				// hit in-memory cache, so it's a known device with old client
				da.AccountID = existing.(deviceAccount).AccountID
				da.Created = existing.(deviceAccount).Created
			} else {
				// missed in-memory cache, should fall back to datastore
				q := datastore.NewQuery("DeviceAccount").
					Ancestor(createDeviceAccountAncestorKey(c)).
					Filter("PushNotificationID =", da.PushNotificationID)
				var existing []*deviceAccount
				keys, err := q.GetAll(c, &existing)
				if err != nil {
					return err
				}

				if len(keys) == 0 {
					// from an unknown device, should create a new account
					key, err := datastore.Put(c, createIncompleteDeviceAccountKey(c), &da)
					if err != nil {
						return err
					}
					da.AccountID = key.IntID()
					daCache.Set(da.PushNotificationID, da)
					return nil
				} else {
					// a known device with old client
					da.AccountID = keys[0].IntID()
					da.Created = existing[0].Created
				}
			}

			_, err := datastore.Put(c, createDeviceAccountKey(c, da.AccountID), &da)
			daCache.Set(da.PushNotificationID, da)
			return err
		} else {
			// update existing account (for request fired by new clients)
			key := strconv.FormatInt(da.AccountID, 10)
			if existing, ok := daCache.Get(key); ok {
				// hit in-memory cache
				da.Created = existing.(deviceAccount).Created
			} else {
				// missed in-memory cache, falls back to datastore
				var existing deviceAccount
				if err := datastore.Get(c, createDeviceAccountKey(c, da.AccountID), &existing); err != nil {
					return err
				}
				da.Created = existing.Created
			}
{'fraction_non_alphanumeric': 0.12039660056657224, 'fraction_numerical': 0.004046944556859571, 'mean_word_length': 3.105481727574751, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4308269', 'n_tokens_mistral': 1905, 'n_tokens_neox': 1565, 'n_words': 443}