Technical Report - nsaid-team/gotopaws GitHub Wiki

Team NSAID

Project: Goto Paws

Team NSAID is Nelma Perera, Sam Morris, Alex Adams, Ian Smith, and Daniela Reyes. Why GotoPaws? It's a lame basic joke.

Introduction

Introduction: Problem

People who are looking to adopt a shelter pet may not know their options when it comes to looking for a shelter to find a pet in, what pets are available in their area, and what pet-centric resources are available in their city.

GotoPaws exists to provide one place for people to find information about shelters in their area, parks, vets, and groomers, as well as pets up for adoption.

Addionally, many people who want to find a specific breed of animal are willing to travel to different cities in order to find their future furball. These people may be doubly unfamiliar with the resources available to them in another city, but with Goto Paws they can find them easily.

Introduction: Use Cases

Case #1: Holly lives in La Vernia, about an hour away from San Antonio, and she wants to adopt a dog. She really has her heart set on a bull terrier, and has been dropping the one local shelter but she can never seem to find one. She'd be willing to travel to a neighboring city but she doesn't know what shelters exist there, and doesn't want to go to the trouble of driving all over a strange town and possibly not find a new bull terrier pal. Using GotoPaws, she's able to get a list of many cities' worth of pets, sortable by breed, and she finds a bull terrier Cookie in foster care in Dallas. She finds Cookie's shelter, calls them and sets up a weekend appointment to drive up and meet him.

Case #2: Winston uses GotoPaws to find a cat in a local shelter. He adopts a Siamese cat, Hamburger, who had been stuck in a shelter because he had some ringworm which scared some potential adopters away. Winston thinks he rocks though and he has been taking care of Hamburger. He's treating him with antifungal provided by the shelter, but he runs out before it clears up. Using GotoPaws Winston finds a veterinarian in his city and books an appointment from their site. After another week of treatment Hamburger is looking good! Winston finds a local groomer to take Hammy to as a celebration.

Case #3: Oscar is a new transplant to Houston after receiving a job offer there. He is renting a new house with a big yard, and is enjoying his new but unfamiliar city. He's also very active and is looking for a dog to be his jogging partner. While he's not particular about breed or age, his lease on his house has a weight limit on pets and he really wants a dog that's no couch potato. Using GotoPaws, he's able to find a medium weight dog, Charlie, at a local shelter as well as a nearby dog park. He's not sure that Charlie's the dog for him, but when he goes to meet Charlie and her foster at the dog park Charlie runs around it like a mad woman. Oscar is super excited to know that she's as high energy as him and they go back to the shelter to sign adoption papers.

Design

Design: RESTful API

We used Apiary to create an API mock and document. Our api documentation is available at (http://docs.gotopaws1.apiary.io/). The API mock server is available at (http://private-300ca-nsaid.apiary-mock.com/) serving mock json responses.

Apiary features GitHub integration, instant API mock, generated documentation, integrated code samples, debugging and automated testing.

Our api features calls that allow outside services to access the data in the json format. Data models used in the gotopaws project include Pets, Shelters, and Cities. All are accessible through the api.

http://private-300ca-nsaid.apiary-mock.com/pets/

Returns a json object including a list of pet dictionaries, including the petsid, name, age, size, breed, shelter, city, and pic_url key/value pairs.

http://private-300ca-nsaid.apiary-mock.com/shelters/

Returns a json object including a list of shelter dictionaries, including the id, name, address1, city, state, phone, email, and pets key/value pairs.

http://private-300ca-nsaid.apiary-mock.com/cities/

Returns a json object including a list of city dictionaries, including the name, state, country, shelters, pets, and vet_url key/value pairs.

Our API Documentation is below:

API Documentation: http://docs.gotopaws1.apiary.io/#

API Blueprint Editor: https://app.apiary.io/gotopaws1/editor

Design: DB Models

Our database models can be viewed in UML form at the (https://github.com/nsaid-team/gotopaws/blob/dev-branch/UML.pdf) location.

The data models used for this project are Pets, Shelters, and Models.

Pets represents a table containing:

  • pet_id, a primary key, a max length 300 CharField django.db.models.Model object
  • pet_name, a max length 300 CharField django.db.models.Model object
  • pet_age, a max length 50 CharField django.db.models.Model object
  • pet_sex, a max length 50 CharField django.db.models.Model object
  • pet_size, a max length 50 CharField django.db.models.Model object
  • pet_breed, a max length 200 CharField django.db.models.Model object
  • pet_shelter, a max length 300 CharField django.db.models.Model object
  • pet_city, a foreign key for the Cities table, a max length 300 CharField django.db.models.Model object
  • pet_city_urlized, a max length 100 CharField django.db.models.Model object
  • pet_state, a max length 50 CharField django.db.models.Model object
  • pet_pic_url, a max length 1000 CharField django.db.models.Model object
  • pet_pic_large, a max length 1000 CharField django.db.models.Model object
  • pet_url, a max length 1000 CharField django.db.models.Model object
  • pet_shelter_url, a max length 1000 CharField django.db.models.Model object
  • pet_city_url, a max length 1000 CharField django.db.models.Model object
  • pet_shelter_name, a max length 300 CharField django.db.models.Model object

Shelters represents a table containing:

  • shelter_id, a primary key, a max length 50 CharField django.db.models.Model object
  • shelter_name, a max length 300 CharField django.db.models.Model object
  • shelter_address, a max length 1000 CharField django.db.models.Model object
  • shelter_city, a foreign key for the Cities table, a max length 300 CharField django.db.models.Model object
  • shelter_city_urlized, a max length 100 CharField django.db.models.Model object
  • shelter_state, a max length 50 CharField django.db.models.Model object
  • shelter_latitude, a max length 50 CharField django.db.models.Model object
  • shelter_longitude, a max length 50 CharField django.db.models.Model object
  • shelter_phone, a max length 50 CharField django.db.models.Model object
  • shelter_email = a max length 200 CharField django.db.models.Model object
  • shelter_hours = a max length 200 CharField django.db.models.Model object
  • shelter_pic = a max length 1000 CharField django.db.models.Model object
  • shelter_url = a max length 1000 CharField django.db.models.Model object
  • shelter_city_url = a max length 1000 CharField django.db.models.Model object
  • shelter_blurb = a max length 1000 CharField django.db.models.Model object

Cities represents a table containing:

  • city_urlized, a max length 300 CharField django.db.models.Model object
  • city_name, part of a composite primary key, a max length 300 CharField django.db.models.Model object
  • city_state, part of a composite primary key, a max length 50 CharField django.db.models.Model object
  • city_country, a max length 200 CharField django.db.models.Model object
  • city_vet_url, a max length 1000 CharField django.db.models.Model object
  • city_groomer_url, a max length 1000 CharField django.db.models.Model object
  • city_park_url, a max length 1000 CharField django.db.models.Model object
  • city_pic, a max length 1000 CharField django.db.models.Model object
  • city_vet_pic, a max length 1000 CharField django.db.models.Model object
  • city_park_pic, a max length 1000 CharField django.db.models.Model object
  • city_groomer_pic, a max length 1000 CharField django.db.models.Model object
  • city_url, a max length 1000 CharField django.db.models.Model object
  • city_blurb, a max length 1000 CharField django.db.models.Model object

TODO: the cities have yet-to-be-implemented lists of vets, dog parks, and groomers. Proof of concept data for these fields has been gathered from api.yelp.com and is currently in github at (https://github.com/nsaid-team/gotopaws/blob/dev-branch/scratch/sfmorris/city_dataset.json).

Clearing and Populating the Database

The command sqlclear will display the commands needed to clear the database and can be piped into the shell with the following command:

python ../manage.py sqlclear nsaid | python ../manage.py dbshell

The command sql <app name> displays the commands needed to create the database tables for the app. The following command will ppipe those commands into the shell:

python ../manage.py sql nsaid | python ../manage.py dbshell

We created a script that will take in json files and populate the database tables automatically. The script needs to be in the same folder as the json files and can be run with the following command:

python ../manage.py shell < json_insert_script.py

Reference: http://eli.thegreenplace.net/2014/02/20/clearing-the-database-with-django-commands

Design: HTML

We mixed and matched templates using Bootstrap-3.3.5-dist (www.getBootstrap.com). The nav-bar is copied statically across each file we make. For phase 1, all of our links are static references to other html pages. The pictures are scraped into our databses and refer to offsite image locations. If the referring website goes down or denies outside referrals, we will lose our images. Our website has a splash page that includes links to 5 other pages, a page for pets, a page for shelters, another for cities and an about page. We recently added a page that exercises the API of our classmates' project. They have a DOTA 2 item site called HatFancy, and we added non-canonical pets to the heroes that can be adopted. Our pets, shelters, and cities pages have sortable tables that hold all the information in our database on each of those object, as well as a link to a personal page for each object. Those pages have a description as well as pictures and links to various related pages both on our website and outside of our website. The Cities page also has outside links to vets, groomers and dog parks. These pages also include a Google map that dynamically searches for the location of the page that you are on. If you are on the San Francisco city page, the map will center on San Francisco. If you are on the Ausitn Pets Alive! page, the map will search google for Austin Pets Alive! and return the resulting map. The query for Google maps is generally in the form q?=<shelter_name><shelter_city>, with all whitespace replaced with + signs. The information for all of those pages are supplied directly from the database through Django. Lastly the about page has information on each member of our team and a picture of each member.

Our pages use icons provided by GlyphSearch: http://glyphsearch.com/

Our pages have imbedded google maps using the following API: https://developers.google.com/maps/documentation/embed/start

Django URL Dispatcher

Whenever a user goes to a URL, either from a link from an html page or from typing it in, Django uses a URL dispatcher to find and load the appropriate html page as well as give that page database information if needed. The Dispatcher works by loading a list of URL patterns that are located in url.py and iterates through the list until it finds a pattern that matches the inputted URL. Each pattern also includes a function, stored in the views.py file, that gets called. The view function loads the appropriate html template and returns that page so Django can load it for the user. For our dynamically allocated html pages, the view function loads a list of objects from our database and renders the html template with that list so the page can display that information. The list of objects have to be in the form of a dictionary.

Design: JavaScript

We use AngularJS to refactor reused code between pages. The most obvious case is the navbar. The repeating code is pulled out into a seperate file called Navbar.html and lives in the templates folder. We have an AngularJS app running on each page labeled "GoToPaws" and using the controller "ExampleController" to run the directives. The javascript code is found in templates.js. To get a navbar on a page, all we have to do is place under our ExampleController and AngularJS will replace that tag with our navbar. This makes our code more maintanable because if we want to change the style or content of the navbar, updating the template page will update every page with a navbar tag.

Nearly all of our database data is brought to the frontend with Django. It is very powerful. So much so, that it hindered our attempts of using AngularJS to manage our content. It seems to run at a higher priority than AngularJS and shares the same interpolaters, "{{" and "}}". We were able to use the $interpolateProvider tag with AngularJS to change its interpolaters to "{[" and "]}", but it was still extremely difficult to work between the two. At one point, we even tried to trick Django into giving us (in AngularJS) the data it had readily available by sending the server an http request and pushing the result to an unused page on our server. Even though this worked, we deemed it too unreasonable and unmaintainable, and we chose to not implement AngularJS in this way.

We learned from this workaround, and when we were required to add functionailty to our "About" page in the form of unit tests, we set up a submit button that makes an http request with AngularJS. Django catches this request, and instead of returning a page, uses python to run the server's bash shell and perform the unit tests on our server. The result is returned into a string and pushed onto a list by AngularJS. The result is updated directly onto the About page.

Design

Each model is made of a header, a small descriptions and a table. The table is real time searchable and sortable in all major fields except for images.

The page External API was made based on Hat Fancy's API. This page provides the visitor an option to adopt his favorite Dota 2 hero's imaginary companion. The table consists of 4 columns where each hero is linked to a corresponding item and item set. We added an extra column consisting of a “companion” which is based on our database of pets. Our visitor is able to click on his desired pet and find its location and information.

The “column” css tag provided by Bootstrap was of great help when aligning elements on the page. Also, text-boxes and text styles were used consistently in order to make our programs readable. One main design choice for our pets was the use of thumbnails or picture galleries in order to show our pets in a standard and clean way.

Our .css files maintain standard sizes of the text or images are been edited throughout the website.

Using large, high resolution images for our background made our site more eye catching; however, it made it harder to find a readable font and text style.

Search Capability

Our website has a search function implemented with Elasticsearch and ElasticUtils. Elasticsearch is an open source search engine that can be found at https://www.elastic.co/products/elasticsearch. ElasticUtils is a python library that allows for an easier integration of Elasticsearch in our site. ElasticUtils even includes code for implementing Elasticsearches with Django and can be found at https://elasticutils.readthedocs.org/en/latest/index.html.

To enable searching on our site, the following command has to be run in the /elasticsearch-1.7.0/bin/ directory of our server.

./elasticsearch

Search Functionality

Each page has a navigation bar with a search field in it. Our search function takes in one or more keywords and returns a list of links to the pages that contain those words. Pages are listed by relevance, in that a page that contains multiple keywords will be places higher than a page that contains just one keyword. Keywords that appear in the text of the pages in the search results are bolded. If the keywords are in the page names then they are in italics.

Installation

To install Elasticsearch we used the instructions on https://www.elastic.co/guide/en/elasticsearch/reference/1.7/_installation.html.

Elasticsearch requires at least Java 7 which we downloaded and installed from http://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html.

ElasticUtils requires python 2.6, 2.7, 3.3 or 3.4 and at least Elasiticsearch 1.0.

Tests

Our unit tests have 4 categories: pet tests, shelter tests, city tests, and api tests. Pet tests create an object and then assert that the values created are equivalent. Shelters and cities do the same, but with their own fields. API tests make api calls, and test for (application/json) response codes. For the pet, shelter, and city tests we test empty values as well as very large values to make sure our database can handle a variety of input.

Platform

We used the rackspace open cloud platform (http://www.rackspace.com/cloud) to host our website on a URL provided by namecheap (https://www.namecheap.com). For server installation and setup we used a presentation by Everett, a rackspace employee (http://everett-toews.github.io/rackspace-developer-doubleplusgood/presentation/#/). Our rackspace VM utilizes Django 1.8.2 to create the framework for our website and to link URLs to html pages (https://www.djangoproject.com).

https://github.com/nsaid-team/gotopaws/wiki

We created two VMs -- a dev VM at 104.130.175.34, reachable from (nsaid.co) and (nsaid.me) and a test vm at IP: 104.130.13.110 reachable from (gotopaws.me).

Platform: VM Setup Instructions

Adapted from http://everett-toews.github.io/rackspace-developer-doubleplusgood/presentation/#/

A note on pricing, a 1GB RAM server costs under $25 a month. Your free developer+ credit of $50 a month for 12 months should allow you to run two servers.

  • Create a Rackspace developer+ account at (mycloud.rackspace.com).

  • Log in to the site and navigate to the "Cloud Control Panel".

  • Click the "Create Server" button at the top of the server list panel.

  • Name the server (we used "gotopaws-test" for our test environment), and select the Northern Virginia (IAD) region.

  • For Image, select Linux > Ubuntu > 15.04 Vivid Vervet.

  • For Flavor select "General Purpose". Select the 1 GB RAM size if it is not already selected and before clicking Create Server select "Advanced Options"*.

  • From "Advanced Options", select "Manage SSH Keys".

  • Copy and paste your public key from ~/yourusername/.ssh/id_rsa.pub if it already exists and paste it to the form. Then, click the "Add Public Key" button. If you don't already have a public key, the "How to get a public key" link will take you to an ssh-keygen tutorial you can use to create a public and private key pair.

  • The server may take up to 2 minutes to build after you create it. It's important to use the following steps to secure the server soon after creating it -- malicious hackers may be wardialing to find newly created VMs in the rackspace IP range.

  • Once the server shows up as active, connect to it by running:

    `ssh -i .ssh/id_rsa [email protected]`
    
  • Once logged in, download and run the secure.sh script. Ask a team member what the username and password to provide to the script should be:

    `wget https://raw.githubusercontent.com/everett-toews/rackspace-developer-doubleplusgood/gh-pages/scripts/secure.sh`  
    `chmod u+x secure.sh`  
    `./secure.sh`
    
  • Log out. Then, log back in as the non-root user:

    `ssh -i .ssh/id_rsa [email protected]`
    
  • Next, download the tools you will need to download, install, and deploy django -- git, pip, and virtualenv. If you're going to be running django under python3 (as we are) you need only install git. The tools can be grabbed from apt-get thus:

    `sudo apt-get -y install git python3-pip`
    
  • point /usr/bin/python at /usr/bin/python3.4

    `sudo rm /usr/bin/python`
    `sudo ln -s /usr/bin/python3.4 /usr/bin/python`
    
  • Install Django pip (adapted from the "Installing an official release with pip" instructions at https://docs.djangoproject.com/en/1.8/topics/install/):

    `sudo pip3 install django==1.8.2`
    

    which will install the django module to /usr/local/lib/python3.4/site-packages/django/.

  • Verify successful installation by running:

    pip freeze

    and look for the "Django==1.8.3" package listed. Also, run:

    sudo find / | grep django

    and verify it installed to the /usr/local/lib/python3.4/site-packages folder.

  • Open port 8000 in the firewall

    `sudo ufw allow 8000`
    
  • Create the django gotopaws project with the django-admin.py script. The script should live in your $PATH already, if not look for it in your my-venv/bin/ folder. Run the script using the startproject argument and the project name, like so:

    django-admin.py startproject gotopaws

    This will create a new /home/nsaid/gotopaws/ folder containing /home/nsaid/gotopaws/manage.py and a /home/nsaid/gotopaws/gotopaws subfolder. Later on we will use the {settings,urls,wsgi}.py files inside this subfolder.

  • Start the server by running:

    python3 manage.py runserver IPADDRESS:PORT

    where IPADDRESS is the ip address of your test server and port could be "80" or "8000", depending on your DNS setup. If you want to run on port 80 you will need to run the above command as sudo.

  • Check that the default page is being served now that the server is up. Open a browser and attempt to go to http://whatevertheipaddressis:theport. If you're unable to hit the page from an outside host, try running

    wget IPADDRESS:PORT

    and troubleshoot from there.

  • Install the djangorestframework which is used by the api app:

    sudo pip install djangorestframework

  • Install the mysql-connector-python package from the multiplay repository:

    sudo pip install git+https://github.com/multiplay/mysql-connector-python
    sudo pip install djutils

  • Install the mysql service, and activate it. When the start script asks you for a password, use the password that we've been sharing.

    sudo apt-get install mysql-server mysql-client

    use a blank password for the mysql root user so travis ci will work.

    sudo service mysql start

  • BONUS ROUND! install vim

    sudo apt-get install vim

    and create a ~/.exrc file with:

    set expandtab set tabstop=4 set shiftwidth=4

  • Stuff a blank password in settings.py in DATABASES.default.PASSWORD

  • start a mysql shell:

    mysql -u root

    and run

    CREATE DATABASE nsaid;

  • clone in to the ~/ dir:

    git clone https://github.com/nsaid-team/gotopaws.git . git fetch git branch git checkout dev-branch git pull

  • MAKE SURE the db name 'nsaid' in DATABASES.default.NAME in setttings.py

  • Settings.py change DATABASES.default.ENGINE to mysql.connector.django

  • make USER 'root'....OTHERWISE SOMETHING WEIRD IS GOING ON WITH YOUR GIT-FU

  • sudo pip3 install git+https://github.com/django-tastypie/django-tastypie

  • python manage.py createsuperuser ?

  • start server

Set up coverage testing in django

##Petfinder

Full petfinder api documentation is available at (https://www.petfinder.com/developers/api-docs). Petfinder allows a variety of GET calls against their api, requiring only simple key authentication (POST, PUT, and DELETE are not implemented at this time). A developer key can be requested from (https://www.petfinder.com/developers/api-key). Obtaining a key will entitle you to:

  • Total requests per day: 10,000
  • Records per request: 1,000
  • Maximum records per search: 2,000

Responses are available in XML (by default) and JSON, which we used (specified using the fomrat=json argument and value). Several calls are available, but these are the ones we used:

  • shelter.find
  • shelter.getPets
  • pet.get

Example call:

http://api.petfinder.com/shelter.get?key=2933122e170793b4d4b60358e67ecb65&id=TX1148&format=json

Example output:

`{
"@encoding": "iso-8859-1",
"@version": "1.0",
"petfinder": {
    "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
    "shelter": {
        "country": {
            "$t": "US"
        },
        "longitude": {
            "$t": "-97.7428"
        },
        "name": {
            "$t": "Small Chance Rescue"
        },
        "phone": {
            "$t": "512-699-7244    "
        },
        "state": {
            "$t": "TX"
        },
        "address2": {},
        "email": {
            "$t": "[email protected]"
        },
        "city": {
            "$t": "Austin"
        },
        "zip": {
            "$t": "78766"
        },
        "fax": {},
        "latitude": {
            "$t": "30.2669"
        },
        "id": {
            "$t": "TX1148"
        },
        "address1": {
            "$t": "P.O. Box 10033"
        }
    },
    "header": {
        "timestamp": {
            "$t": "2015-07-21T21:49:55Z"
        },
        "status": {
            "message": {},
            "code": {
                "$t": "100"
            }
        },
        "version": {
            "$t": "0.1"
        }
    },
    "@xsi:noNamespaceSchemaLocation": "http://api.petfinder.com/schemas/0.9/petfinder.xsd"
}
}`

##Yelp

The yelp api documentation is available at (https://www.yelp.com/developers/documentation/v2/overview)

Consumer Key KUvBeJ9O5nV23Bg5lBGLUA Consumer Secret K-xQZ9Y8moKw1C71Qsn61MaM0t0 Token VchJDQRV1LyH_ZHoawrotybgyuuVN-IW Token Secret eWqGCYQrFV9QcE2Ok6LuTvx6p7g

API v1.0 (deprecated) YWSID Key Y8oEk4_tEQD_vJIEgXj3Gg

We weren't able to grab these with just a rest call in a browser on account of oauth, so we created a short python script, dataset_creator.py, to rely on python modules to do it for us.

Google Search API

We used calls to (http://ajax.googleapis.com/ajax/services/search/web) to grab the external urls for shelters, since they were unavailable via the yelp api.

Scraping strategy

Our strategy for scraping APIs was to iterate over a static list of 5 cities, and use the Petfinder API to find several shelters per city. We would then grab several attributes from our petfinder request, and use the attributes of that request to further query the google api for a link to the shelter website, and query the yelp api for a short blurb describing the shelter. Then we wrote the final shelter objects to nsaid/fixtures/shelters_fixture.json.

Once we had a fixture file for our shelters, we parsed it, and iterated over the shelters, running a series of shelter.getPets calls to grab up to 10 pets per shelter. We created json objects out of the pets and dumped them to nsaid/fixtures/shelters_fixture.json with the appropriate fixture heading (https://docs.djangoproject.com/en/1.8/howto/initial-data/).

Finally, we created a city fixture file by iterating over the city list, and running a series of yelp queries to grab the top rated veterinarians, pet groomers, and dog parks in each city.

Each call also required that we use python replaces to sanitize the json of unicode characters so the charsets would play nicely with mysql, and to trim extra newlines so when the frontend of our site eventually displayed the objects they were formatted nicely.

Once we had fixture files, we were able to completely drop all tables, recreate them, and reload all of our json-backed records with the following commands:

 `python manage.py sqlclear nsaid | python manage.py dbshell ; python manage.py sql nsaid | python manage.py dbshell`
 `python ~/gotopaws/manage.py loaddata ~/gotopaws/nsaid/fixtures/{cities,shelters,pets}_fixture.json`

It was handy!

GotoPaws

API Documentation: http://docs.gotopaws1.apiary.io/#

API Blueprint Editor: https://app.apiary.io/gotopaws1/editor

Future Improvements:

Support for a Larger Dataset

We will need to have dynamic model pages that can be loaded with any set of information from the database. This also means we will have to expand our database to include information like bios and google map code.

Backup Pictures

Eventually we will need to store backups of all of our images rather than getting all the images directly from the internet. Those images could be taken down and then we would not be able to retrieve them unless we have backups.

Ensure Browser Compatibility

Our site needs to be designed so that any browser will view the information properly as well as being viewable on mobile devices.

Dead Link Checking

Our site needs to have every link function properly.

Adding More Models

Each City has information on vets, groomers and parks and it may be beneficial to make models for each of these and even have their own pages.

API Improvements

We could add author authorization so others can improve upon the API. Another improvement would be to allow getting an individual model by ID, currently a user can get an entire list but not an individual. We also can include requests in our API so an authorized user could update the database through our API.

Post Mortem

Post Mortem: Team Workflow

We created a development branch, dev-branch, and a master branch. Most of our commits are in dev-branch and are thus not listed on the About page: (https://help.github.com/articles/why-are-my-contributions-not-showing-up-on-my-profile/). For a group of 5, our plan was to meet from noon-8 or 9 or midnight and frequently after in GDC every day since Thursday, with the provision that if you couldn't make it in one day, keep an eye on slack as much as possible and meet the next day. It seemed to work fairly well, though to do it over again it would have been much more beneficial to all decide on a site map the first day and all work towards that goal from day 1. We didn't create one until Saturday.

https://github.com/nsaid-team/gotopaws/wiki/Hours-Spent

My advice to future teams is to tentatively pick a data set (almost without exception it should be pullable from an api), and once you have decided on a topic/data create a site map the first day you all meet. Then, sort through the data and find what attributes are available and use that information to populate the site map with actual variable names. Frontend and backend teams should be working towards that goal from then on. We had to redesign our models several times because they didn't fit the project spec and/or weren't distinct data models (at one point our models were to be Shelters/Dogs/Cats).

We would also advise future teams that after deciding a topic, gathering data, and creating a site map any implementation discussions that last longer than an hour should be tabled until TA advice can be sought.

Looking at previous years' teams projects was also helpful.

Post Mortem: Problems

  • We spent way too much time trying to get angular to play nicely with our json data. We spent a considerable amount of time gathering data sets and building cherry-picked toy datasets to hand off to the frontend team so they had a concrete data structure to start referencing. In the end it needs to be done, but not for the proof-of-concept phase. We attempted several different implementations. First we created a 3 pet json file, a 3 shelter json file, and a 3 city json file. The idea was to have each of the pages loading the json in their controllers and have the modules use that to generate content. We had problems getting the json to load in to the controllers. We also attempted to copy/paste the json objects in to the controllers directly but could not get that implemented either. If we were to start over, we would have written static html files for the whole site and added bits and pieces of angular from there probably would have been more successful and less stressful.

  • Everyone we talked to in the lab said they couldn't get get pydoc to work with models.py -- they were all getting the same error importing django.db.

  • Our authorized_keys file was empty on our production server this morning. Pub key authentication had been working for all team members since Friday and miraculously broke.

⚠️ **GitHub.com Fallback** ⚠️