Skip to content

inTouch is an application that creates suggestions for which of your contacts you should call/send a message to, based on their priority and desired frequency of contact. This application builds endpoints for the inTouch-FE application to consume

Notifications You must be signed in to change notification settings

ryan-mcneil/inTouch-BE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Waffle.io - Columns and their card count

Description

If you're like most people, it's getting harder and harder to create and nurture deep, meaningful relationships as we transfer our social lives to digital media. If you're like most people, you want to do something about it.

InTouch is a minimalist app designed to help you stay connected with people you care about. It's not a social media network or an automated communications system. You don't set it and forget it. It's more like a friend who reminds you to reach out to your loved ones now and then in meaningful ways.

This is the official backend application for InTouch. Check out the frontend repo here!

API Documentation

Making Requests

Request Formatting

  • Because it's a GraphQL API, all requests should be POST requests
  • All requests are sent to the endpoint /api/v1/data
  • "query" and "variables" key-value pairs are sent in the body

Examples are formatted for readability. In practice, header and body values should be stripped of any line breaks. For example, for the query:

query {
  contacts {
    id
    name
  }
}

Send the following JSON formatted key/value pair:

{ "query": "query { contacts { id name } }" }

The same is true for mutations.

{ "query": "mutation {... }" }

And if you need to send variables with the request:

{
  "query": "mutation CreateTestContact($contactInput: ContactInput!){ createContact(input:$contactInput){ ok contact { name } } }",
  "variables": "{ \"contactInput\": {\"frequency\": 10, \"name\": \"Joey\"} }"
}

User Creation and Authentication

This app is secured using Django's default user authentication and JSON Web Tokens (JWT).

Create a New User

Send a createUser request to create a new user account:

mutation {
  createUser(email:"me@me.com", username:"myself", password:"mypassword"){
    user{
      username
    }
  }
}

Authenticate an existing user

When an account has been created, send a tokenAuth request to authenticate the user and get a JWT:

mutation {
  tokenAuth(username:"myself", password:"myself"){
    token
  }
}

This will return :

{
  "data": {
    "tokenAuth": {
      "token": "%user-access-token%"
    }
  }
}

This token is used for Authorization of future requests.

Authorize a Request

Endpoints requiring authorization (i.e. the rest of them) must be sent with the header:

"Authorization": "JWT %user-access-token%"

Queries

All queries are scoped to the user making the request, which is determined by the JWT sent in the Authorization header.

Contacts

A query can be made for all of a user's contacts with any or all of the following attributes:

query {
  contacts {
    id
    name
    frequency
    priority
    nextReminder
    lastContacted
    notes
    contactDetails {
      id
      label
      value
      preferred
    }
    occasions {
      id
      description
      date
    }
  }
}

JSON Response (limited attributes):

{
  "data": {
    "contacts": [
      {
        "id": "1",
        "name": "Mom",
        "contact_details": [
          {
            "label": "phone",
            "value": "123-456-7890",
            "preferred": true
          }
        ],
        "occasions": [
          {
            "description": "birthday",
            "date": "1970-02-28"
          }
        ]
      },
      {
        "id": "2",
        "name": "Dad"
      }
    ]
  }
}

Single Contact

A single contact with id = 1 can be queried with any of the same attributes:

query {
  contact(id: 1) {
    id
    name
    frequency
    priority
    nextReminder
    lastContacted
    notes
    contactDetails {
      id
      label
      value
      preferred
    }
    occasions {
      id
      description
      date
    }
  }
}

JSON Response (limited attributes shown):

{
  "data": {
    "contact": {
      "id": "1",
      "name": "Mom",
      "contact_details": [
        {
          "label": "phone",
          "value": "123-456-7890",
        }
      ],
      "occasions": [
      	{
          "description": "birthday",
          "date": "1970-02-28"
      	}
      ]
    }
  }
}

Suggested Contacts

A query can be made for suggested contacts, determined by nextReminder and priority, for a user specified leadTime = 7 (days), with any or all of the following attributes:

query {
  contactSuggestions(leadTime: 7) {
    id
    name
    frequency
    priority
    nextReminder
    lastContacted
    notes
    contactDetails {
      id
      label
      value
      preferred
    }
    occasions {
      id
      description
      date
    }
  }
}

JSON Response (limited attributes shown):

{
  "data": {
    "contactSuggestions": [
      {
        "id": "1",
        "name": "Mom",
        "contact_details": [
          {
            "label": "phone",
            "value": "123-456-7890",
            "preferred": true
          }
        ],
        "occasions": [
          {
            "description": "birthday",
            "date": "1970-02-28"
          }
        ]
      },
      {
        "id": "2",
        "name": "Dad"
      }
    ]
  }
}

Mutations

Create Contact

A contact can be created with a name (required) and any additional attributes with the following query:

mutation CreateContact($input:CreateContactInput!) {
  createContact(input:$input){
    ok
    contact {
      name
    }
  }
}

and variables:

{
  "input": {
    "name": "Dad",
    "notes": "Some Notes"
  }
}

JSON Response:

{
  "data": {
    "createContact": {
      "ok": true,
      "contact": {
        "name": "Dad"
      }
    }
  }
}

Update Contact

A contact can be updated by providing the contact id and any or all attributes with the following query:

mutation UpdateContact($id:Int!, $input:UpdateContactInput!) {
  updateContact(id:$id, input:$input){
    ok
    contact {
      name
    }
  }
}

and variables:

{
  "input": {
    "name": "Father",
    "priority": "3",
    "lastContacted": "2019-03-02",
    "notes": "Some New Notes",
  },
  "id": 3
}

JSON Response:

{
  "data": {
    "updateContact": {
      "ok": true,
      "contact": {
        "name": "Father"
      }
    }
  }
}

Delete Contact

A contact can be deleted by providing the contact id with the following query:

mutation DeleteContact($id:Int!) {
  deleteContact(id:$id){
    ok
  }
}

and variables:

{
  "id": 3
}

JSON Response:

{
  "data": {
    "deleteContact": {
      "ok": true,
    }
  }
}

Create Contact Detail

A contact detail must be created with a label and value with the following query:

mutation CreateContactDetail($contact_id:Int!, $input:CreateContactDetailInput!) {
  createContactDetail(contactId:$contact_id, input:$input){
    ok
    contactDetail {
      label
    }
  }
}

and variables:

{
  "input": {
    "label": "Phone",
    "value": "303-123-4567"
  },
  "contact_id": 1
}

JSON Response:

{
  "data": {
    "createContactDetail": {
      "ok": true,
      "contactDetail": {
        "label": "Phone"
      }
    }
  }
}

Update Contact Detail

A contact detail can be updated with a new label and/or value with the following query:

mutation updateContactDetail($id:Int!, $input:UpdateContactDetailInput!) {
  updateContactDetail(id:$id, input:$input){
    ok
    contactDetail {
      label
    }
  }
}

and variables:

{
  "input": {
    "label": "Cell",
    "value": "303-123-4568"
  },
  "id": 1
}

JSON Response:

{
  "data": {
    "updateContactDetail": {
      "ok": true,
      "contactDetail": {
        "label": "Cell"
      }
    }
  }
}

Delete Contact Detail

A contact detail can be deleted by providing the contact detail id with the following query:

mutation DeleteContactDetail($id:Int!) {
  deleteContactDetail(id:$id){
    ok
  }
}

and variables:

{
  "id": 3
}

JSON Response:

{
  "data": {
    "deleteContactDetail": {
      "ok": true,
    }
  }
}

Create Occasion

A occasion must be created with a description and date with the following query:

mutation CreateOccasion($contact_id:Int!, $input:CreateOccasionInput!) {
  createOccasion(contactId:$contact_id, input:$input){
    ok
    occasion {
      description
    }
  }
}

and variables:

{
  "input": {
    "description": "birthday",
    "date": "1960-05-07"
  },
  "contact_id": 1
}

JSON Response:

{
  "data": {
    "createOccasion": {
      "ok": true,
      "occasion": {
        "description": "birthday"
      }
    }
  }
}

Update Occasion

A occasion can be updated with a new description and/or date with the following query:

mutation updateOccasion($id:Int!, $input:UpdateOccasionInput!) {
  updateOccasion(id:$id, input:$input){
    ok
    occasion {
      description
    }
  }
}

and variables:

{
  "input": {
    "description": "birthday",
    "date": "1960-05-07"
  },
  "id": 1
}

JSON Response:

{
  "data": {
    "updateOccasion": {
      "ok": true,
      "occasion": {
        "description": "birthday"
      }
    }
  }
}

Delete Occasion

A occasion can be deleted by providing the occasion id with the following query:

mutation DeleteOccasion($id:Int!) {
  deleteOccasion(id:$id){
    ok
  }
}

and variables:

{
  "id": 3
}

JSON Response:

{
  "data": {
    "deleteOccasion": {
      "ok": true,
    }
  }
}

For Contributors

Backend Tech Stack

  • Django v2.1.7
  • Python v3.2.7
  • GraphQL with Graphene v2.1.3
  • PostgreSQL v11.1

Getting Started

This is an ongoing OpenSource project that we want to make as useful as possible without experiencing feature bloat. Contributions are welcome and encouraged! To make it as easy as possible for future contributors, we're committed to keeping our test-coverage high and our tech-debt low, so pull requests will be thoroughly reviewed and vetted before merging.

Setup

Set up a virtual debug environment where-ever you want it to live, then activate it:

$ python3 -m venv $PATH_TO_VENV/dj-env
$ echo "export DEBUG=True" >> $PATH_TO_VENV/dj-env/postactivate
$ source <PATH_TO_VENV>/bin/activate

We like to make a dj-env for Django specifically. The second command creates a script to run after the virtual environment is activated. You can also set up Django specific bash aliases in this file.

The DEBUG=True is used in settings.py to use a generic secret_key for local development.

Next, clone down the repo and install dependencies:

$ git clone git@github.com:ryan-mcneil/inTouch-BE.git
$ cd inTouch-BE
$ pip install -r requirements.txt

Set up a local database:

$ psql
=> CREATE DATABASE in_touch_dev

Then run migrations:

$ python manage.py migrate

Now you should be able to run the server locally:

$ python manage.py runserver

Visit http://localhost:8000/api/v1/data to interact using the GraphiQL GUI and view the schema documentation. We recommend creating a superuser for your local server:

$ python manage.py createsuperuser

After that, you can visit http://localhost:8000/admin and log in. The admin account you log in as will be used for authenticating any requests made through the GraphiQL interface. To directly manipulate the authorization header, we recommend using Insomnia, which was designed with GraphQL in mind. Postman is an excellent choice also.

Pull Requests

When you make changes you want to incorporate, please submit a PR to the dev branch. We have a live staging deployment on Heroku that we use to check new functionality and compatibility before deploying to master and deploying to production. (At the moment, we actually don't have a production deployment, but we will soon!)

Core Team

About

inTouch is an application that creates suggestions for which of your contacts you should call/send a message to, based on their priority and desired frequency of contact. This application builds endpoints for the inTouch-FE application to consume

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages