Commit b8947bb8 authored by Tom Gordon's avatar Tom Gordon

finished implementing all the use cases for working with cases in a way which...

finished implementing all the use cases for working with cases in a way which is independent of the domain model.
parent c37a4eb8
{
"Description": "Model of the dimensions of automobiles",
"Issue": "Choosing a car to buy",
"Options": [
"buy",
"do_not_buy"
],
"Statements": {
"buy": "Buy this car.",
"do_not_buy": "Do not buy this car.",
"low_price": "The car is low priced.",
"medium_price": "The car is medium priced.",
"high_price": "The car is high priced.",
"sports_car": "The car is a sports car.",
"family_car": "The car is a family car.",
"sedan": "The car is a sedan.",
"low_speed": "The car is slow.",
"medium_speed": "The car is of medium speed.",
"fast_speed": "The car is fast.",
"low_safety": "The car has low safety.",
"medium_safety": "The car is medium safe.",
"high_safety": "The car is highly safe."
},
"Dimensions": {
"price": {
"Default": "medium_price",
"Description": "Price",
"Factors": [
"low_price",
"medium_price",
"high_price"
]
},
"type": {
"Default": "sedan",
"Description": "Type",
"Factors": [
"sports_car",
"family_car",
"sedan"
]
},
"speed": {
"Default": "medium_speed",
"Description": "Speed",
"Factors": [
"slow_speed",
"medium_speed",
"fast_speed"
]
},
"safety": {
"Default": "medium_safety",
"Description": "Safety",
"Factors": [
"low_safety",
"medium_safety",
"high_safety"
]
}
}
}
......@@ -41,5 +41,11 @@ func main() {
log.Fatal(err)
}
web.ArgumentationToolServer(*httpPort, *couchdbURL, domainsDBName, casesDBName, templatesDir)
cdb := web.CouchDBConfig{
URL: *couchdbURL,
Domains: domainsDBName,
Cases: casesDBName,
}
web.ArgumentationToolServer(*httpPort, cdb, templatesDir)
}
......@@ -7,12 +7,13 @@
package model
type Case struct {
Id string `json:"_id"`
Meta struct {
Id string `json:"_id"`
Revision string `json:"_rev"`
Meta struct {
Title string `json:"title"`
Citation string `json:"citation"`
Court string
Decided string
Year string // Year Decided
Description string
Keywords string
Language string
......
......@@ -2,7 +2,7 @@
"_id" : "_design/cases",
"views" : {
"statement" : {
"map" : "function(doc) { var l = {}; for (var s in doc.statements) { l[s] = doc.statements[s] }; emit(doc._id, { \"title\": doc.meta.title, \"decided\": doc.meta.decided, \"statements\": l }); }"
"map" : "function(doc) { var l = {}; for (var s in doc.statements) { l[s] = doc.statements[s] }; emit(doc._id, { \"title\": doc.meta.title, \"year": doc.meta.year, \"statements\": l }); }"
}
}
}
\ No newline at end of file
......@@ -8,13 +8,15 @@ package web
import (
"encoding/json"
"html/template"
"io/ioutil"
"net/http"
"path"
)
func makeDeleteCaseHandler(couchdbURL string, dbName string, errorTemplate *template.Template, templatesDir string) func(http.ResponseWriter, *http.Request) {
func makeDeleteCaseHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
dbName := cdb.Cases
errorTemplate := tc.errorTemplate
return func(w http.ResponseWriter, req *http.Request) {
caseId := path.Base(req.URL.Path)
......@@ -51,7 +53,5 @@ func makeDeleteCaseHandler(couchdbURL string, dbName string, errorTemplate *temp
defer resp.Body.Close()
http.Redirect(w, req, "/", http.StatusSeeOther)
// home := &templateHandler{filename: ".html", templatesDir: templatesDir}
// home.ServeHTTP(w, nil)
}
}
// Copyright © 2016 Thomas F. Gordon
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
package web
import (
// "fmt"
"git.list.lu/eagle/argumentation-tool/internal/model"
"html/template"
"net/http"
"path"
"path/filepath"
)
func makeEditCaseFormHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
casesDBName := cdb.Cases
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
return func(w http.ResponseWriter, req *http.Request) {
domainId := path.Base(path.Dir(req.URL.Path))
caseId := path.Base(req.URL.Path)
domain, err := model.GetDomain(couchdbURL, domainsDBName, domainId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
case1, err := model.GetCase(couchdbURL, casesDBName, caseId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
currentCase := map[string]interface{}{
"DomainId": domainId,
"Id": case1.Id,
"Revision": case1.Revision,
"Title": case1.Meta.Title,
"Citation": case1.Meta.Citation,
"Court": case1.Meta.Court,
"Year": case1.Meta.Year,
"Description": case1.Meta.Description,
"Keywords": case1.Meta.Keywords,
"Language": case1.Meta.Language,
"Majority": case1.Meta.Majority,
"Minority": case1.Meta.Minority,
"Options": make(map[string]Option),
"Dimensions": make(map[string]Dimension),
}
// get the decision and dimensions of the current case
for k, s := range case1.Statements {
d, ok := domain.FactorDimension(k)
// assumption: at most one factor of each dimension is in
if ok && s.Label == "in" {
dimensions := currentCase["Dimensions"].(map[string]Dimension)
factors := []Factor{}
for _, f := range domain.Dimensions[d].Factors {
factors = append(factors, Factor{Id: f, Text: domain.FactorStatement(f), Selected: f == k})
}
dimensions[d] = Dimension{Id: d, Description: domain.Dimensions[d].Description, Factors: factors}
}
for _, p := range domain.Options {
if k == p {
// the statement is an option of the issue of the model
in := false
if s.Label == "in" {
in = true
}
options := currentCase["Options"].(map[string]Option)
options[p] = Option{Statement: s.Text, In: in}
}
}
}
t := template.Must(template.ParseFiles(filepath.Join(templatesDir, "case-editor.html")))
t.Execute(w, currentCase)
}
}
......@@ -16,7 +16,11 @@ import (
"path/filepath"
)
func makeListDomainsHandler(couchdbURL string, domainsDBName string, errorTemplate *template.Template, templatesDir string) func(http.ResponseWriter, *http.Request) {
func makeListDomainsHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
return func(w http.ResponseWriter, req *http.Request) {
// Retrieve the list of domain models from CouchDB
resp, err := http.Get(couchdbURL + "/" + domainsDBName + "/_all_docs")
......
......@@ -11,14 +11,16 @@ import (
"github.com/carneades/carneades-4/src/engine/caes"
"github.com/carneades/carneades-4/src/engine/caes/encoding/dot"
"github.com/carneades/carneades-4/src/engine/caes/encoding/json"
"html/template"
"io/ioutil"
"net/http"
"os/exec"
"path"
)
func makeMapCaseHandler(couchdbURL string, dbName string, errorTemplate *template.Template, templatesDir string) func(http.ResponseWriter, *http.Request) {
func makeMapCaseHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
dbName := cdb.Cases
errorTemplate := tc.errorTemplate
return func(w http.ResponseWriter, req *http.Request) {
caseId := path.Base(req.URL.Path)
......
// Copyright © 2016 Thomas F. Gordon
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
package web
import (
// "fmt"
"git.list.lu/eagle/argumentation-tool/internal/model"
"html/template"
"net/http"
"path"
"path/filepath"
)
func makeNewCaseFormHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
return func(w http.ResponseWriter, req *http.Request) {
domainId := path.Base(req.URL.Path)
domain, err := model.GetDomain(couchdbURL, domainsDBName, domainId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
t := template.Must(template.ParseFiles(filepath.Join(templatesDir, "new-case-form.html")))
t.Execute(w, domain)
}
}
......@@ -9,94 +9,116 @@ package web
import (
"bytes"
"encoding/json"
// "fmt"
"git.list.lu/eagle/argumentation-tool/internal/model"
// "github.com/carneades/carneades-4/src/engine/caes"
"github.com/carneades/carneades-4/src/engine/caes"
// "github.com/carneades/carneades-4/src/engine/caes/encoding/dot"
cj "github.com/carneades/carneades-4/src/engine/caes/encoding/json"
"github.com/pborman/uuid"
"html/template"
"io/ioutil"
"net/http"
// "os/exec"
"path/filepath"
"strconv"
)
func makeNewCaseHandler(couchdbURL string, dbName string, errorTemplate, newCaseCreatedTemplate *template.Template) func(w http.ResponseWriter, req *http.Request) {
func makeNewCaseHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
casesDBName := cdb.Cases
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
newCaseCreatedTemplate := template.Must(template.ParseFiles(filepath.Join(templatesDir, "new-case-created.html")))
return func(w http.ResponseWriter, req *http.Request) {
ag := cj.NewArgGraph()
ag.Meta["title"] = req.FormValue("title")
ag.Meta["citation"] = req.FormValue("citation")
ag.Meta["decided"] = req.FormValue("decided")
ag.Meta["court"] = req.FormValue("court")
ag.Meta["majority"] = req.FormValue("majority")
ag.Meta["minority"] = req.FormValue("minority")
ag.Meta["keywords"] = req.FormValue("keywords")
ag.Meta["language"] = req.FormValue("language")
// ag.Meta["license"] = req.FormValue("license")
ag.Meta["description"] = req.FormValue("description")
possession := false
if req.FormValue("decision") == "possession" {
possession = true
ag := caes.NewArgGraph()
// ag.Metadata["domain"] = req.FormValue("domainId")
ag.Metadata["title"] = req.FormValue("title")
ag.Metadata["citation"] = req.FormValue("citation")
ag.Metadata["year"] = req.FormValue("year")
ag.Metadata["court"] = req.FormValue("court")
ag.Metadata["majority"] = req.FormValue("majority")
ag.Metadata["minority"] = req.FormValue("minority")
ag.Metadata["keywords"] = req.FormValue("keywords")
ag.Metadata["language"] = req.FormValue("language")
ag.Metadata["description"] = req.FormValue("description")
domainId := req.FormValue("domainId")
domain, err := model.GetDomain(couchdbURL, domainsDBName, domainId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
possessionLabel := "out"
noPossessionLabel := "in"
if possession {
possessionLabel = "in"
noPossessionLabel = "out"
}
decision := req.FormValue("decision")
// add the premises to the statement table
for dimension, _ := range animals.AnimalsModel.Dimensions {
ag.Statements[req.FormValue(dimension)] =
cj.Statement{Text: animals.AnimalsModel.FactorStatement(req.FormValue(dimension)),
Label: "in"}
// and assume them to be true
for dimension, _ := range domain.Dimensions {
factor := req.FormValue(dimension)
ag.Statements[factor] =
&caes.Statement{Id: factor, Text: domain.FactorStatement(factor),
Label: caes.In}
ag.Assumptions[factor] = true
}
// take note of the premises, which are all the statements
// add thus far to the statements table
premises := []interface{}{}
for k, _ := range ag.Statements {
premises = append(premises, k)
// added thus far to the statements table
premises := []caes.Premise{}
for _, s := range ag.Statements {
premises = append(premises, caes.Premise{Stmt: s})
}
// add the conclusions of the arguments, constructed next below,
// to the statements table
// construct the issue
ag.Statements["possession"] = cj.Statement{
Text: "The party claiming possession did have possession.",
Label: possessionLabel,
}
i1 := caes.NewIssue()
i1.Id = "i1"
ag.Issues[i1.Id] = i1
ag.Statements["no-possession"] = cj.Statement{
Text: "The party claiming possession did not have possession.",
Label: noPossessionLabel,
}
// add the conclusions of the arguments, constructed next below,
// to the statements table
ag.Arguments["a1"] = cj.Argument{
Scheme: "possession-scheme",
Premises: []interface{}(premises),
Conclusion: "possession",
for i, option := range domain.Options {
label := caes.Out
if option == decision {
label = caes.In
}
conclusion := caes.Statement{
Id: option,
Text: domain.FactorStatement(option),
Label: label,
Args: []*caes.Argument{},
}
ag.Statements[option] = &conclusion
arg := caes.NewArgument()
arg.Id = "a" + strconv.Itoa(i)
arg.Scheme = caes.BasicSchemes["cumulative"]
arg.Premises = premises
arg.Conclusion = &conclusion
ag.Arguments[arg.Id] = arg
conclusion.Args = append(conclusion.Args, arg)
i1.Positions = append(i1.Positions, &conclusion)
}
ag.Arguments["a2"] = cj.Argument{
Scheme: "no-possession-scheme",
Premises: []interface{}(premises),
Conclusion: "no-possession",
// validate the argument graph
err = validate(ag)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
// construct the issue
// export the argument graph to JSON
ag.Issues["i1"] = cj.Issue{
Positions: []string{"possession", "no-possession"},
Standard: "PE",
cag, err := cj.Caes2Json(ag)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
// upload the JSON document to Couchdb
id := uuid.NewUUID().String()
req2, err := http.NewRequest("PUT", couchdbURL+dbName+"/"+id, bytes.NewBufferString(ag.String()))
req2, err := http.NewRequest("PUT", couchdbURL+casesDBName+"/"+id, bytes.NewBufferString(cag.String()))
if err != nil {
errorTemplate.Execute(w, err.Error())
return
......@@ -132,13 +154,12 @@ func makeNewCaseHandler(couchdbURL string, dbName string, errorTemplate, newCase
return
}
// Provide the user with feedback by displaying an
// argument map, in SVG formt, for the argument graph of the
// case entered. To validate that the graph has been correctly
// stored in Couchdb, first read the JSON back in
// from the Couchdb repository.
data := map[string]string{
"DomainId": domainId,
"CaseId": id,
}
newCaseCreatedTemplate.Execute(w, id)
newCaseCreatedTemplate.Execute(w, data)
}
}
// Copyright © 2015 Thomas F. Gordon
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
package web
import (
"bytes"
"encoding/json"
"git.list.lu/eagle/argumentation-tool/internal/model"
"github.com/carneades/carneades-4/src/engine/caes"
// "github.com/carneades/carneades-4/src/engine/caes/encoding/dot"
cj "github.com/carneades/carneades-4/src/engine/caes/encoding/json"
"html/template"
"io/ioutil"
"net/http"
// "os/exec"
"fmt"
"path/filepath"
"strconv"
"strings"
)
func makeSaveCaseHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
casesDBName := cdb.Cases
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
caseSavedTemplate := template.Must(template.ParseFiles(filepath.Join(templatesDir, "case-saved.html")))
return func(w http.ResponseWriter, req *http.Request) {
ag := caes.NewArgGraph()
// ag.Metadata["domain"] = req.FormValue("domainId")
ag.Metadata["title"] = req.FormValue("title")
ag.Metadata["citation"] = req.FormValue("citation")
ag.Metadata["year"] = req.FormValue("year")
ag.Metadata["court"] = req.FormValue("court")
ag.Metadata["majority"] = req.FormValue("majority")
ag.Metadata["minority"] = req.FormValue("minority")
ag.Metadata["keywords"] = req.FormValue("keywords")
ag.Metadata["language"] = req.FormValue("language")
ag.Metadata["description"] = req.FormValue("description")
domainId := req.FormValue("domainId")
domain, err := model.GetDomain(couchdbURL, domainsDBName, domainId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
decision := req.FormValue("decision")
// add the premises to the statement table
// and assume them to be true
for dimension, _ := range domain.Dimensions {
factor := req.FormValue(dimension)
ag.Statements[factor] =
&caes.Statement{Id: factor, Text: domain.FactorStatement(factor),
Label: caes.In}
ag.Assumptions[factor] = true
}
// take note of the premises, which are all the statements
// added thus far to the statements table
premises := []caes.Premise{}
for _, s := range ag.Statements {
premises = append(premises, caes.Premise{Stmt: s})
}
// construct the issue
i1 := caes.NewIssue()
i1.Id = "i1"
ag.Issues[i1.Id] = i1
// add the conclusions of the arguments, constructed next below,
// to the statements table
for i, option := range domain.Options {
label := caes.Out
if option == decision {
label = caes.In
}
conclusion := caes.Statement{
Id: option,
Text: domain.FactorStatement(option),
Label: label,
Args: []*caes.Argument{},
}
ag.Statements[option] = &conclusion
arg := caes.NewArgument()
arg.Id = "a" + strconv.Itoa(i)
arg.Scheme = caes.BasicSchemes["cumulative"]
arg.Premises = premises
arg.Conclusion = &conclusion
ag.Arguments[arg.Id] = arg
conclusion.Args = append(conclusion.Args, arg)
i1.Positions = append(i1.Positions, &conclusion)
}
// validate the argument graph
err = validate(ag)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
// export the argument graph to JSON
cag, err := cj.Caes2Json(ag)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
// upload the JSON document to Couchdb
rev := req.FormValue("revision")
id := req.FormValue("caseId")
// add a field for revision number to the JSON representation of
// the argument graph
json1 := cag.String()
json2 := strings.Replace(json1, "{", "{\"_rev\":\""+rev+"\",", 1)
req2, err := http.NewRequest("PUT", couchdbURL+casesDBName+"/"+id, bytes.NewBufferString(json2))
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
client := http.Client{}
resp, err := client.Do(req2)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
defer resp.Body.Close()
// check that uploading was successful
m := make(map[string]interface{})
v, err := ioutil.ReadAll(resp.Body)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
err = json.Unmarshal(v, &m)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
// m should have the form:
// {"ok":true,"id":"6e1295ed6c29495e54cc05947f18c8af","rev":"1-2902191555"}
if m["ok"] != true {
errorTemplate.Execute(w, fmt.Sprintf("Couchdb: %v\n", m))
return
}
data := map[string]string{
"DomainId": domainId,
"CaseId": id,
}
caseSavedTemplate.Execute(w, data)
}
}
......@@ -7,37 +7,24 @@
package web
import (
"encoding/json"
// "fmt"
"git.list.lu/eagle/argumentation-tool/internal/model"
"html/template"
"io/ioutil"
"net/http"
"path"
"path/filepath"
)
func makeSearchFormHandler(couchdbURL string, dbName string, errorTemplate *template.Template, templatesDir string) func(http.ResponseWriter, *http.Request) {
func makeSearchFormHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
return func(w http.ResponseWriter, req *http.Request) {
domainId := path.Base(req.URL.Path)
url := couchdbURL + dbName + "/" + domainId
resp, err := http.Get(url)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
}
domain := model.Domain{}
err = json.Unmarshal(body, &domain)
domain, err := model.GetDomain(couchdbURL, domainsDBName, domainId)
if err != nil {
errorTemplate.Execute(w, err.Error())
return
......
......@@ -43,7 +43,12 @@ func (a BySimilarity) Less(i, j int) bool {
return a[i].Similarity >= a[j].Similarity
}
func makeSearchHandler(couchdbURL string, domainsDBName string, casesDBName string, errorTemplate *template.Template, templatesDir string) func(http.ResponseWriter, *http.Request) {
func makeSearchHandler(cdb CouchDBConfig, tc TemplatesConfig) func(http.ResponseWriter, *http.Request) {
couchdbURL := cdb.URL
domainsDBName := cdb.Domains
casesDBName := cdb.Cases
errorTemplate := tc.errorTemplate
templatesDir := tc.templatesDir
return func(w http.ResponseWriter, req *http.Request) {
// this is the only reference to the animals model,
// making it easier to generalize this code to all domain models later
......
<!DOCTYPE html>
<html>
<head>
<title>EAGLE Argumentation Tool: Case Editor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">