<repo_name>wanghedi1991/cs6675-mobAlarm<file_sep>/MobAlarm/appserver/admin.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib import admin

from .models import User, Location
# Register your models here.

class LocationAdmin(admin.ModelAdmin):
	list_display = ['category', 'name', 'latitude', 'longitude', 'grid_id', 'address']

class UserAdmin(admin.ModelAdmin):
	list_display = ['username','last_grid_id']

admin.site.register(Location, LocationAdmin)
admin.site.register(User, UserAdmin)<file_sep>/MobAlarm/appserver/datamanager.py
from __future__ import unicode_literals
import requests
from django.db import models
from appserver.models import User, Location
from appserver.gridmanager import computeGridId, computeNearbyGridId, getLocationsInGrids, computeInnterBox, range_dict, computeNearbyGridIdwithDirection, handle_location


google_place_api = '<KEY>'
place_search_api_prefix = 'https://maps.googleapis.com/maps/api/place/radarsearch/json?location=33.775622,-84.398473&radius=5000&type='
place_detail_api_prefix = 'https://maps.googleapis.com/maps/api/place/details/json?placeid='

category_list = ['supermarket', 'gasstation', 'postoffice', 'atm', 'shoppingmall']


def downloadDataFromGoogle(password, category):
    if password == '<PASSWORD>':
        url = place_search_api_prefix + category + '&key=' + google_place_api
        r = requests.get(url)
        results = r.json()['results']

    else:
        res_status = dict(status='fail')
        return res_status

    for item in results:

        place_id = item['place_id']
        lat = item['geometry']['location']['lat']
        lng = item['geometry']['location']['lng']

        if lng < range_dict['left'] or lng > range_dict['right'] or lat < range_dict['bottom'] or lat > range_dict[
            'top']:
            continue

        detail_url = place_detail_api_prefix + place_id + '&key=' + google_place_api
        detail_r = requests.get(detail_url)
        detail_result = detail_r.json()['result']

        business_address = detail_result['formatted_address']
        business_name = detail_result['name']
        business_grid_id = computeGridId(lat, lng)
        # business_description = ???

        new_business = Location(category=category, name=business_name, grid_id=business_grid_id, latitude=lat, longitude=lng,
                            address=business_address)
        new_business.save()

    res_status = dict(status='success', numOfResult=len(results))
    return res_status
    <file_sep>/mobile/Location Notifier/Location Notifier/FirstViewController.swift
//
//  FirstViewController.swift
//  Location Notifier
//
//  Created by <NAME> on 3/14/18.
//  Copyright © 2018 <NAME>. All rights reserved.
//

import UIKit

class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate {

    @IBOutlet weak var typePicker: UIPickerView!
    @IBOutlet weak var notificationTypeTable: UITableView!
    var types:[NotificationType] = []
    var addList:[NotificationType] = [Constant.testType0, Constant.testType1, Constant.testType2]
    var tempType:Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let parentController = self.tabBarController as! TableHolderController
        types = parentController.notificationTypes
        
        self.notificationTypeTable.delegate = self
        self.notificationTypeTable.dataSource = self
        self.notificationTypeTable.tableFooterView = UIView()
        
        self.typePicker.dataSource = self
        self.typePicker.delegate = self
        setNavigationBar()
    }
    
    
    func setNavigationBar(){
        (self.tabBarController as! TableHolderController).navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: UIBarButtonItemStyle.plain, target: self, action: #selector(addNotificationType))
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.types.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "notificationTypeCell", for: indexPath) as! NotificationTypeCell
        cell.nameLabel.text = types[indexPath.row].name
        return cell
    }
    
    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {


        let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete", handler: { (action, indexPath) in
            self.types.remove(at: indexPath.row)
            (self.tabBarController as! TableHolderController).notificationTypes.remove(at: indexPath.row)
            self.notificationTypeTable.reloadData()
        })
        deleteAction.backgroundColor = UIColor.red
        
        return [deleteAction]
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return addList.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return addList[row].name
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        self.tempType = row
    }
    
    
    @IBAction func addNotificationType(_ sender: UIBarButtonItem) {
     //   self.doneButton.isHidden = false
        if self.typePicker.isHidden {
            self.typePicker.isHidden = false
            self.notificationTypeTable.isHidden = true
            sender.title = "Done"
        } else {
            self.typePicker.isHidden = true
            self.notificationTypeTable.isHidden = false
            if self.types.contains(addList[tempType]) {
                showToast(message: "It is already added")
            } else {
                self.types.append(addList[tempType])
                (self.tabBarController as! TableHolderController).notificationTypes.append(addList[tempType])
                self.notificationTypeTable.reloadData()
            }
            sender.title = "Add"
        }
    }
    
}

extension UIViewController {
    
    func showToast(message : String) {
        
        let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: self.view.frame.size.height-100, width: 150, height: 35))
        toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
        toastLabel.textColor = UIColor.white
        toastLabel.textAlignment = .center;
        toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
        toastLabel.text = message
        toastLabel.alpha = 1.0
        toastLabel.layer.cornerRadius = 10;
        toastLabel.clipsToBounds  =  true
        self.view.addSubview(toastLabel)
        UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
            toastLabel.alpha = 0.0
        }, completion: {(isCompleted) in
            toastLabel.removeFromSuperview()
        })
    }
}




<file_sep>/MobAlarm/MobAlarm/urls.py
"""MobAlarm URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from appserver import views
urlpatterns = [
	url(r'^register/username=(?P<username>.*)&password=(?P<password>.*)',views.user_register, name = 'user_register'),
    url(r'^login/username=(?P<username>.*)&password=(?P<password>.*)',views.user_login, name = 'user_login'),
	url(r'^add/username=(?P<username>.*)&category=(?P<category>.*)', views.add_event, name = 'add_event'),
	url(r'^delete/username=(?P<username>.*)&category=(?P<category>.*)', views.delete_event, name = 'delete_event'),
	url(r'^location/username=(?P<username>.*)&latitude=(?P<latitude>[+-]?(\d*\.)?\d+)&longitude=(?P<longitude>[+-]?(\d*\.)?\d+)', views.handle_location_without_angle, name = 'handle_location_without_angle'),
    url(r'^location/username=(?P<username>.*)&latitude=(?P<latitude>[+-]?(\d*\.)?\d+)&longitude=(?P<longitude>[+-]?(\d*\.)?\d+)&angle=(?P<angle>[+-]?(\d*\.)?\d+)', views.handle_location_with_angle, name = 'handle_location_with_angle'),
	url(r'^processdata/password=(?P<password>.*)/category=(?P<category>.*)', views.process_data, name = 'process_data'),
    url(r'^admin/', admin.site.urls),
]
<file_sep>/MobAlarm/appserver/views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render

from django.shortcuts import render
from django.http import HttpResponse
from django.http import Http404
from django.http import JsonResponse
from appserver.models import User, Location



from appserver.datamanager import downloadDataFromGoogle, category_list
from appserver.gridmanager import computeGridId, computeNearbyGridId, getLocationsInGrids, computeInnterBox, range_dict, computeNearbyGridIdwithDirection, handle_location


import bz2
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User as U
from django.contrib.auth.decorators import login_required




def user_register(request, username, password):
    # response with fail message if username exist
    try:
        user = U.objects.get(username=username)
        encrypted_password = None
    except U.DoesNotExist:
        user = None
        encrypted_password = <PASSWORD>(password.encode('utf-8'))

    if user is not None:
        status = dict(type='post_response', status='fail', reason='username has already been used')
        return JsonResponse(status, safe=False)

    # register auth user
    new_u = U(username=username, password=<PASSWORD>)
    new_u.save()

    # add new user to User table
    new_user = User(username=new_u)
    new_user.save()

    # print(new_user.username)

    status = dict(type='post_response', status='succeed', reason='register succeeded')
    return JsonResponse(status, safe=False)


def user_login(request, username, password):
    user, u = verifyUser(username)
    print(user)

    input_password = str(bz2.compress(password.encode('utf-8')))
    # print(input_password)


    # test = authenticate(username='ll')
    # print(test)

    # reponse with fail message if username does not exist
    if u is None:
        status = dict(type='post_response', status='fail', reason='user does not exist')
        return JsonResponse(status, safe=False)

    # check password
    if u is not None and input_password != <PASSWORD>:
        # print("wrong password")
        status = dict(type='post_response', status='fail', reason='wrong password')
        return JsonResponse(status, safe=False)

    # login
    login(request, u)
    status = dict(type='post_response', status='succeed', reason='user login succeeded')
    return JsonResponse(status, safe=False)


# @login_required(login_url='/login/')
def add_event(request, username, category):
    user, u = verifyUser(username)

    # if not request.user.is_authenticated:
    #     print("here")

    # reponse with fail message if username does not exist
    if user is None:
        status = dict(type='post_response', status='fail', reason='user does not exist')
        return JsonResponse(status, safe=False)

    # reponse with fail message if category is not supported
    if category not in category_list:
        status = dict(type='post_response', status='fail', reason='wrong category')
        return JsonResponse(status, safe=False)
    # register user with the category
    user.__dict__[category] = True
    user.save()
    status = dict(type='post_response', status='succeed', reason='event is added successfully')
    return JsonResponse(status, safe=False)


def delete_event(request, username, category):
    user, u = verifyUser(username)

    # reponse with fail message if username does not exist
    if user is None:
        status = dict(type='post_response', status='fail', reason='user does not exist')
        return JsonResponse(status, safe=False)
    # reponse with fail message if categories does not exist
    if category not in category_list:
        status = dict(type='post_response', status='fail', reason='wrong category')
        return JsonResponse(status, safe=False)
    # unregister user with the category
    user.__dict__[category] = False
    user.save()
    status = dict(type='post_response', status='succeed', reason='event is deleted successfully')

    # status = dict(type = 'post_response', status = 'succeed', reason = 'event is deleted successfully')
    return JsonResponse(status, safe=False)



def handle_location_with_angle(request, username, latitude, longitude, angle):
    user, u = verifyUser(username)
    status = handle_location(user, latitude, longitude, angle)

    return JsonResponse(status, safe=False)

def handle_location_without_angle(request, username, latitude, longitude):
    user, u = verifyUser(username)
    status = handle_location(user, latitude, longitude, angle = -1)
    return JsonResponse(status, safe=False)


# admin method for grabbing location data from GOOGLE API, and put locationw with grid_id into online database
# !!!!!!!!!!!!DO NOT run this function, or database may get in trouble!!!!!!!!!!!
def process_data(request, password, category):
    status = downloadDataFromGoogle(password, category)
    return JsonResponse(status, safe=False)






# the function is for user authentication
def verifyUser(username):
    try:
        u = U.objects.get(username=username)
        user = User.objects.get(username=u)
    except U.DoesNotExist:
        u = None
        user = None
    return user, u
<file_sep>/README.md
# cs6675-mobAlarm

## Prerequisit:
1. python 3.x
2. django 1.11.11 or laters
3. mysqlclient 1.3.7 or laters

## To Run on your mac
1. pip install django
2. pip install mysqlclient
3. mkdir cs6675-mobAlarm
4. cd cs6675-mobAlarm
5. git clone https://github.com/Rwang721/cs6675-mobAlarm.git
6. cd MobAlarm
7. python manage.py runserver

## Client-Server Interaction:
please see google drive 6675document.docx

## Now support category:
[atm, suppermarket, postoffice, shoppingmall, gasstation]

## To-Do Lists:
1. Support more categories
2. User authentitcation
3. Client IOS app that support:
   (1) User safe register/login
   (2) Add/Delete Event
   (3) Location Notification


## For windows:
who knows...



<file_sep>/MobAlarm/appserver/models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import User as U
from django.conf import settings

# Create your models here.

class User(models.Model):
	# username = models.CharField(max_length = 100)
	username = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
	# password = models.TextField(null = True)
	last_grid_id = models.IntegerField(default = -1)
	supermarket = models.BooleanField(default = False)
	gasstation = models.BooleanField(default = False)
	atm = models.BooleanField(default = False)
	postoffice = models.BooleanField(default = False)
	shoppingmall = models.BooleanField(default = False)



class Location(models.Model):
	category = models.CharField(max_length = 100)
	name = models.CharField(max_length = 200)
	grid_id = models.IntegerField(db_index = True)
	latitude = models.DecimalField(decimal_places = 6, max_digits = 8)
	longitude = models.DecimalField(decimal_places = 6, max_digits = 8)
	address = models.TextField(null = True)
	description = models.TextField(null = True, blank = True)
    <file_sep>/mobile/Location Notifier/Location Notifier/LoginViewController.swift
//
//  LoginViewController.swift
//  Location Notifier
//
//  Created by <NAME> on 3/24/18.
//  Copyright © 2018 <NAME>. All rights reserved.
//

import UIKit

class LoginViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var loginLabel: UILabel!
    @IBOutlet weak var usernameLabel: UILabel!
    @IBOutlet weak var usernameText: UITextField!
    
    @IBOutlet weak var passwordTextField: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        usernameText.delegate = self
        //self.navigationItem.titleView = UIImageView(image: UIImage(named: "title_small.png"))
        self.navigationItem.title = "Login Page"
        let loginItem = UIBarButtonItem(title: "Login", style: UIBarButtonItemStyle.plain, target: self, action: #selector(loginButtonPressed))
        
        self.navigationItem.rightBarButtonItem = loginItem
        self.navigationController?.navigationBar.tintColor = UIColor.white
    
        usernameText.leftViewMode = UITextFieldViewMode.always
        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
        let image = UIImage(named: "user.png")
        imageView.image = image
        usernameText.leftView = imageView
        
        passwordTextField.leftViewMode = UITextFieldViewMode.always
        let imageViewPassword = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
        let imagePassword = UIImage(named: "password.png")
        imageViewPassword.image = imagePassword
        passwordTextField.leftView = imageViewPassword
        passwordTextField.delegate = self
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        usernameText.endEditing(true)
        return true
    }
    
    @IBAction func loginButtonPressed(_ sender: UIButton) {
        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let newViewController = storyBoard.instantiateViewController(withIdentifier: "tableHolderController") as! TableHolderController
        self.navigationController?.pushViewController(newViewController, animated: true)
    }
    

}
<file_sep>/MobAlarm/appserver/gridmanager.py
from __future__ import unicode_literals

from django.db import models
from appserver.models import User, Location
category_list = ['supermarket', 'gasstation', 'postoffice', 'atm', 'shoppingmall']

# neighbor grids in grid system
dx = [1, 0, -1]
dy = [1, 0, -1]

num_of_col = 66
num_of_row = 66
# atlanta boundary
range_dict = dict(top=33.875448, bottom=33.575448, left=-84.563182, right=-84.263182)

# given coordinates, compute the grid_id
def computeGridId(lat, lng):
    # the gird has 44 rows and 66 cols
    row = int((range_dict['top'] - float(lat)) * 110000) // 500
    col = int((float(lng) - range_dict['left']) * 110000) // 500
    print(row, col)

    return row * num_of_col + col



#input a clockwise angle from the north, in the range[0, 360)
def computeNearbyGridIdwithDirection(lat, lng, angle):
    grid_id = computeGridId(lat, lng)

    row_id = grid_id // num_of_col
    col_id = grid_id % num_of_col
    result = []

    if (angle >= 0 and angle < 45) or (angle >= 315 and angle < 360) :
        for i in range(-1, 2):
            for j in (-1, 1):
                x = row_id + i
                y = col_id + j

                if x >= 0 and y >= 0 and x < num_of_row and y < num_of_col:
                    result.append(x * num_of_col + y)

    elif angle >= 45 and angle < 135:
        for i in range(0, 2):
            for j in (-1, 2):
                x = row_id + i
                y = col_id + j

                if x >= 0 and y >= 0 and x < num_of_row and y < num_of_col:
                    result.append(x * num_of_col + y)

    elif angle >= 135 and angle < 225:
        for i in range(-1, 2):
            for j in (0, 2):
                x = row_id + i
                y = col_id + j

                if x >= 0 and y >= 0 and x < num_of_row and y < num_of_col:
                    result.append(x * num_of_col + y)

    elif angle >=225 and angle < 315:
        for i in range(-1, 1):
            for j in (-1, 2):
                x = row_id + i
                y = col_id + j

                if x >= 0 and y >= 0 and x < num_of_row and y < num_of_col:
                    result.append(x * num_of_col + y)
    return result


# given a grid_id, given all the neighbors' gird_id
def computeNearbyGridId(lat, lng):
    grid_id = computeGridId(lat, lng)

    row_id = grid_id // num_of_col
    col_id = grid_id % num_of_col

    result = []

    for i in range(-1, 2):
        for j in range(-1, 2):
            x = row_id + i
            y = col_id + j

            if x >= 0 and y >= 0 and x < num_of_row and y < num_of_col:
                result.append(x * num_of_col + y)

    return result


# return satisfying locations
def getLocationsInGrids(nearbyGridIds, userEvents):
    print(nearbyGridIds)
    print(userEvents)

    locations = Location.objects.filter(grid_id__in=nearbyGridIds).filter(category__in=userEvents)

    return locations


# compute the innerbox
def computeInnterBox(nearbyLocations, grid_id, user_lat, user_lng):
    row_id = grid_id // num_of_col
    col_id = grid_id % num_of_col

    # the 3*3 gird neighborhood servers as a default box
    top = min(range_dict['top'] - ((row_id - 1) * 0.0045), range_dict['top'])
    bottom = max(range_dict['top'] - ((row_id + 2) * 0.0045), range_dict['bottom'])
    left = max(range_dict['left'] + ((col_id - 1) * 0.0045), range_dict['left'])
    right = min(range_dict['left'] + ((col_id + 2) * 0.0045), range_dict['right'])

    results = []

    # the innerbox shrinks as testing each candidate locations in the 3*3 neighborhood
    for location in nearbyLocations:
        l = float(location.longitude) - 0.0005
        r = float(location.longitude) + 0.0005
        t = float(location.latitude) + 0.0005
        b = float(location.latitude) - 0.0005
        print(l, r, t, b, location.longitude, location.latitude)

        # Locations in user's range will not be considered for computing the innerbox, they will be added to the result lists.
        if user_lat < t and user_lat > b and user_lng < r and user_lng > l:
            item = dict(name=location.name, category=location.category, latitude=location.latitude,
                        longitude=location.longitude, description="Blank")
            results.append(item)
            continue

        if l > user_lng and l < right:
            right = l

        if r < user_lng and r > left:
            left = r

        if b > user_lat and b < top:
            top = b

        if t < user_lat and t > bottom:
            bottom = t

    return dict(top=top, bottom=bottom, left=left, right=right), results

def handle_location(user, latitude, longitude, angle = -1):
     # reponse with fail message if username does not exist
    if user is None:
        status = dict(type='post_response', status='fail', reason='user does not exist')
        return status

    lng = float(longitude)
    lat = float(latitude)

    # reponse with fail message if user is not in supporte area
    if lng < range_dict['left'] or lng > range_dict['right'] or lat < range_dict['bottom'] or lat > range_dict['top']:
        status = dict(type='post_response', status='fail', reason='user out of range')
        return status

    # update user's current grid_id
    user.last_grid_id = computeGridId(latitude, longitude)
    user.save()

    userEvents = []

    # get all register event of the user
    for category in category_list:
        if user.__dict__[category] is True:
            userEvents.append(category)

    # compute nearby grids
    if angle == -1:
        nearbyGridIds = computeNearbyGridId(latitude, longitude)
    else:
        nearbyGridIds = computeNearbyGridIdwithDirection(latitude, longitude, angle)
   
    # compute locations in nearby grids
    nearbyLocations = getLocationsInGrids(nearbyGridIds, userEvents)

    # compute the request-free inner box for the user, and a set of notifiable results
    innerbox, results = computeInnterBox(nearbyLocations, user.last_grid_id, lat, lng)

    # reponse with results and the innerbox
    status = dict(type='result_set', box=innerbox, numberOfResult=len(results), results=results)
    return status



<file_sep>/mobile/Location Notifier/Location Notifier/TableHolderController.swift
//
//  tableHolderController.swift
//  Location Notifier
//
//  Created by <NAME> on 3/25/18.
//  Copyright © 2018 <NAME>. All rights reserved.
//

import UIKit
class TableHolderController: UITabBarController, UITabBarControllerDelegate {

    var notificationTypes:[NotificationType] = [Constant.testType0, Constant.testType1, Constant.testType2]
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.navigationItem.title = "Notification Categories"
        self.delegate = self
    }
    
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        print(String(self.selectedIndex))
        if self.selectedIndex == 0 {
            (viewController as! FirstViewController).setNavigationBar()
        } else if selectedIndex == 1 {
            (viewController as! SecondViewController).setNavigationBar()
        }
    }
   

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */
    

}
