Skip to content
This repository was archived by the owner on Dec 8, 2017. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d7cfe41
initial buildout of rules engine backend
Jun 20, 2017
c82bb70
add req file
Jun 20, 2017
af250bf
move out pseduo-tests and add in RulesInstance class
Jun 20, 2017
16b3cb5
create the very beginnings of a test file
Jun 20, 2017
ea3a8bc
incoporate flask, create some routes, forms
Jun 20, 2017
d343d87
add missing dependency
Jun 20, 2017
dede0eb
move static files to datastore
Jun 20, 2017
dfa5c6a
build out front end, other things
Jun 20, 2017
ff958f5
make create rules page more human readable
Jun 21, 2017
4d0b32f
add in calculation module
Jun 22, 2017
5bdad6a
link rules and calculations, plus some fixes and handling of non-stri…
Jun 22, 2017
322434c
refactor a good bit, break out db-like operations to sep module, simp…
Jun 23, 2017
4a3d02c
add simple read/write api
Jun 23, 2017
84011a9
refactor routes, add v basic api docs
Jun 27, 2017
5a1bb8e
add basic unit and api integration testing
Jun 27, 2017
51162ee
add jquery for now
Jun 28, 2017
1ebc422
partial for base, remove table from create prototypes
Jun 28, 2017
173b593
add help text
Jun 28, 2017
61b7174
add some things to gitignore
Jun 29, 2017
ea31a45
break calculations into partials; add styling
Jun 29, 2017
e167b85
add alerts and WIP rules
Jun 29, 2017
764f806
basic styling on most pages
Jun 29, 2017
1fe4b01
some radio buttons
Jun 29, 2017
c15efe9
fix calc assemblage for multi value calcs
Jul 18, 2017
134c788
Merge pull request #11 from 18F/add-styling
batemapf Aug 3, 2017
5325420
Merge pull request #9 from 18F/flask-build
batemapf Aug 3, 2017
a013a0c
update readme
Aug 3, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__
node_modules
*.pyc
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# opm-faces

## Report
Our final report and recommendations may be found on [18F's Google Drive](https://drive.google.com/open?id=0B8u6AetkKiTUM0RIVEZZbkI2WTQ).

## Magic Rules!
As part of our engagement, we created a very basic prototype business rules calculator to demonstrate
a few of the concepts and patterns that were included in our recommendations:
- Store rules as data, not as code
- Choose a single, consolidated place for calculations to be executed
- Loosen up coupling between the calculation engine and any front end components to allow for component switch out

To run Magic Rules, just clone this repository to your local machine navigate to `/magic_rules` and execute
`magic.py`. The various data types ("prototypes", "calculations", and "rules") are written to `/magic_rules/datastore`
when created via the web interface. Magic Rules also has a simple read/write API that is documented in `/api/`.

## Contributing

See [CONTRIBUTING](CONTRIBUTING.md) for additional information.
Expand Down
69 changes: 69 additions & 0 deletions magic_rules/api/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## /api
### Request structure
Method(s): GET

*No payload or parameters required.*

### Call
```
curl -X GET http://127.0.0.1:5000/api
```
### Response
```
{
"endpoints": [
{
"actions": [
{
"method": "GET",
"route": "./read"
},
{
"method": "POST",
"route": "./write"
}
],
"route": "/prototypes"
},
{
"actions": [
{
"method": "GET",
"route": "./read"
},
{
"method": "POST",
"route": "./write"
}
],
"route": "/calculations"
},
{
"actions": [
{
"method": "GET",
"route": "./read"
},
{
"method": "POST",
"route": "./write"
}
],
"route": "/rules"
},
{
"actions": [
{
"method": "GET",
"route": "./read"
},
{
"method": "POST",
"route": "./write"
}
],
"route": "/data"
}
]
}
```
58 changes: 58 additions & 0 deletions magic_rules/api/sections/calculations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## /api/calculations/read
### Request structure
Method(s): GET
*No payload or parameters required.*
### Call
```
curl -X GET http://127.0.0.1:5000/api/calculations/read
```
### Response
```
{
"double_height": {
"data": "2*__height__",
"name": "double_height",
"type": "calc"
}
}
```
## /api/calculations/write
### Request structure
Method(s): POST
```
{
"object": "",
"name": "",
"contingent": "",
"static_value_0": "",
"attribute_value_0": "",
"operator_value_0": "",
"static_value_1": "",
"attribute_value_1": "",
"operator_value_1": "",
"static_value_2": "",
"attribute_value_2": "",
"operator_value_2": "",
"attribute_value_3": "",
"static_value_3": "",
"operator_value_3": "",
"static_value_4": "",
"attribute_value_4": "",
"operator_value_4": "",
"static_value_5": "",
"attribute_value_5": "",
...
}
```
### Call
```
curl -H "Content-Type: application/json" -X POST -d '{"name":"double_height", "object":"animal", "contingent": "TRUE", "static_value_0":"2", "attribute_value_0":"", "operator_value_0":"*","static_value_1":"", "attribute_value_1":"__height__"}' http://127.0.0.1:5000/api/calculations/write
```
### Response
```
{
"data": "2*__height__",
"name": "double_height",
"type": "calc"
}
```
47 changes: 47 additions & 0 deletions magic_rules/api/sections/data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## /api/rules/read
### Request structure
Method(s): GET
*No payload or parameters required.*
### Call
```
curl -X GET http://127.0.0.1:5000/api/data/read
```
### Response
```
[
{
"height": "4",
"rules": [
"test_tall"
],
"test_tall": "8",
"type": "animal"
}
]
```

## /api/data/write
### Request structure
Method(s): POST
```
{
"type": "",
... # Any attributes available from the prototype.

}
```
### Call
```
curl -H "Content-Type: application/json" -X POST -d '{"type":"animal","height":"4"}' http://127.0.0.1:5000/api/data/write
```
### Response
```
{
"height": "4",
"rules": [
"test_tall"
],
"test_tall": "8",
"type": "animal"
}
```
48 changes: 48 additions & 0 deletions magic_rules/api/sections/prototypes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## /api/prototypes/read
### Request structure
Method(s): GET
*No payload or parameters required.*
### Call
```
curl -X GET http://127.0.0.1:5000/api/prototypes/read
```
### Response
```
{
"animal": {
"height": null,
"rules": [
"test_tall"
],
"type": "animal"
}
}
```
## /api/prototypes/write
### Request structure
Method(s): POST
```
{
"name": "",
"attribute_0": "",
"attribute_1": "",
"attribute_2": "",
"attribute_3": "",
"attribute_4": "",
...
}
```
### Call
```
curl -H "Content-Type: application/json" -X POST -d '{"name":"animal","attribute_0":"height"}' http://127.0.0.1:5000/api/prototypes/write
```
### Response
```
{
"animal": {
"height": null,
"rules": [],
"type": "animal"
}
}
```
56 changes: 56 additions & 0 deletions magic_rules/api/sections/rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## /api/rules/read
### Request structure
Method(s): GET
*No payload or parameters required.*
### Call
```
curl -X GET http://127.0.0.1:5000/api/rules/read
```
### Response
```
{
"test_tall": {
"attribute": "height",
"compare_value": "5",
"concur": "_double_height",
"name": "test_tall",
"not_concur": "tall enough already",
"operator": "<=",
"type": "logic"
}
}
```
## /api/rules/write
### Request structure
Method(s): POST
```
{
"name": "",
"object": "",
"operator": ""
"attribute": "",
"compare_value": "",
"concur_static": "",
"concur_calc": "",
"not_concur_calc": "",
"not_concur_static": "",
}
```
### Call
```
curl -H "Content-Type: application/json" -X POST -d '{"name":"test_tall", "object":"animal", "operator":"<=", "attribute":"height", "compare_value":"5", "concur_static":"", "concur_calc":"_double_height", "not_concur_static":"tall enough already", "not_concur_calc":""}' http://127.0.0.1:5000/api/rules/write
```
### Response
```
{
"test_tall": {
"attribute": "height",
"compare_value": "5",
"concur": "_double_height",
"name": "test_tall",
"not_concur": "tall enough already",
"operator": "<=",
"type": "logic"
}
}
```
29 changes: 29 additions & 0 deletions magic_rules/datastore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#! /usr/bin/env python3
import json

class MagicDB:
def __init__(self, filename):
self.filename = filename
self.data = self.read()

def read(self):
with open(self.filename, 'r') as infile:
return json.loads(infile.read())

def write(self, to_write):
with open(self.filename, 'w') as outfile:
outfile.write(json.dumps(to_write, indent=4))

def all(self):
return self.data

def single(self, key):
return self.data[key]

def update(self, data, key):
self.data[key] = data
self.write(self.data)

def add(self, data):
self.data.append(data)
self.write(self.data)
1 change: 1 addition & 0 deletions magic_rules/datastore/calculations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions magic_rules/datastore/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
1 change: 1 addition & 0 deletions magic_rules/datastore/objects.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions magic_rules/datastore/rules.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Loading