233 lines
6.5 KiB
Julia
233 lines
6.5 KiB
Julia
using JSON, BibTeX
|
|
# Downloading
|
|
using URIParser, HTTP
|
|
#=
|
|
Mapping between zotero and BibTeX.
|
|
=#
|
|
|
|
# https://github.com/retorquere/zotero-better-bibtex/blob/master/translators/Better%20BibLaTeX.ts
|
|
|
|
"Map zotero reference types to bibtex"
|
|
const zotero_type_map = Dict(
|
|
"artwork" => "artwork",
|
|
"audioRecording" => "audio",
|
|
"bill" => "legislation",
|
|
"blogPost" => "online",
|
|
"book" => "book",
|
|
"bookSection" => "incollection",
|
|
"case" => "jurisdiction",
|
|
"computerProgram" => "software",
|
|
"conferencePaper" => "inproceedings",
|
|
"dictionaryEntry" => "inreference",
|
|
"document" => "misc",
|
|
"email" => "letter",
|
|
"encyclopediaArticle" => "misc", # "inreference",
|
|
"film" => "movie",
|
|
"forumPost" => "online",
|
|
"hearing" => "jurisdiction",
|
|
"instantMessage" => "misc",
|
|
"interview" => "misc",
|
|
"journalArticle" => "article",
|
|
"letter" => "letter",
|
|
"magazineArticle" => "article",
|
|
"manuscript" => "unpublished",
|
|
"map" => "misc",
|
|
"newspaperArticle" => "article",
|
|
"patent" => "patent",
|
|
"podcast" => "audio",
|
|
"presentation" => "unpublished",
|
|
"radioBroadcast" => "audio",
|
|
"report" => "report",
|
|
"statute" => "legislation",
|
|
"thesis" => "thesis",
|
|
"tvBroadcast" => "video",
|
|
"videoRecording" => "video",
|
|
"webpage" => "online"
|
|
)
|
|
# , subtype: "magazine"},
|
|
# , subtype: "newspaper"},
|
|
|
|
|
|
"Map zotero fields to bibtex fields"
|
|
const zotero_field_map = Dict(
|
|
"title" => "title",
|
|
"pages" => "pages",
|
|
"DOI" => "DOI",
|
|
"ISSN" => "ISSN",
|
|
"publisher" => "publisher",
|
|
"publicationTitle" => "journal",
|
|
"date" => "year",
|
|
"volume" => "volume",
|
|
"issue" => "number"
|
|
# FIXME: ADD TAGS?
|
|
)
|
|
|
|
"Parses the `creatorType` field and creates a string with authors"
|
|
function creatortoauthor(c::Dict)
|
|
ctype = c["creatorType"]
|
|
if ctype != "author"
|
|
error("Add this creator type($(ctype)) to the supported ones!")
|
|
end
|
|
"""{$(c["lastName"]), $(c["firstName"])}"""
|
|
end
|
|
|
|
"Takes all zotero creators, converts and join them"
|
|
authors(c) = join(creatortoauthor.(c), " and ")
|
|
|
|
#=
|
|
Functions used to interface with the zotero connector
|
|
=#
|
|
|
|
"""Creates the response by using the response body `res`, the default
|
|
`headers` and the headers to add (`extraheaders`).
|
|
|
|
Defines the hook `set_headers` (before setting them) and
|
|
`post_headers_merge` (before sending the response)
|
|
"""
|
|
function setzoteroheaders(res, extraheaders::Dict)
|
|
@hook :set_headers
|
|
newheaders = merge(headers, extraheaders)
|
|
@hook :post_headers_merge (newheaders,)
|
|
Dict(:headers => newheaders, :body => res)
|
|
end
|
|
|
|
"""
|
|
The zotero connector sometimes pings the program to see if we are listening (e.g., before sending the data). This must support both GET and POST.
|
|
|
|
Defines the hook `ping`
|
|
"""
|
|
function pong(app)
|
|
@hook :ping
|
|
if app[:method] == "POST"
|
|
headers = Dict("Content-Type" => "application/json")
|
|
# FIXME: get(libraries[currentlibrary],"autosnapshot", false)
|
|
response = json(Dict("prefs" =>
|
|
Dict("automaticSnapshots" =>
|
|
false
|
|
)))
|
|
else
|
|
headers = Dict("Content-Type" => "text/html")
|
|
response = """
|
|
<!DOCTYPE html><html><head>
|
|
<title>Zotero Connector Server is Available</title></head>
|
|
<body>Zotero Connector Server is Available</body></html>"""
|
|
end
|
|
|
|
response, headers
|
|
end
|
|
|
|
"""
|
|
|
|
Defines the hook `get_collection`
|
|
"""
|
|
function collection(any, libraries, currentlibrary)
|
|
@hook :get_collection
|
|
libraryName = "developing"
|
|
|
|
json(Dict(
|
|
"libraryID" => 1,
|
|
"libraryName" => "default",
|
|
"libraryEditable" => !libraries[currentlibrary]["readonly"],
|
|
"editable" => true, # collection-level parameters
|
|
"id" => 1, # collection-level
|
|
"name" => currentlibrary
|
|
)), Dict("Content-Type" => "application/json")
|
|
end
|
|
|
|
"""
|
|
Save page snapshot.
|
|
|
|
Defines the hooks `pre_save_snapshot` and `post_save_snapshot`.
|
|
"""
|
|
function savesnapshot(req, libraries, currentlibrary)
|
|
@hook :pre_save_snapshot
|
|
if libraries[currentlibrary]["readonly"]
|
|
warn("Library is readonly")
|
|
return "no", Dict()
|
|
end
|
|
|
|
parsed = JSON.parse(String(req[:data]))
|
|
if !parsed["skipSnapshot"]
|
|
info("Saving page snapshot")
|
|
open("./devel/snapshot.html", "w") do f
|
|
write(f, parsed["html"])
|
|
end
|
|
else
|
|
info("NOT saving page snapshot")
|
|
end
|
|
@hook :post_save_snapshot
|
|
"savesnapshot", Dict()
|
|
end
|
|
|
|
"""
|
|
Download (asynchronously) all the attachments.
|
|
|
|
Defines `pre_get_attachment` and `post_get_attachment`
|
|
"""
|
|
function getattachment(id, attachment)
|
|
@hook :pre_get_attachment
|
|
title = attachment["title"]
|
|
url = attachment["url"]
|
|
|
|
mime = nothing
|
|
if "mimeType" in keys(attachment)
|
|
mime = MIME(attachment["mimeType"])
|
|
end
|
|
|
|
name = basename(URI(url).path)
|
|
name == "" && (name = title * ".html")
|
|
path = expanduser(libraries[currentlibrary]["path"])
|
|
mkpath("$path/$id")
|
|
file = "$path/$id/$name"
|
|
try
|
|
# FIXME: we should tell zotero-connector which is a success and which isn't
|
|
@spawn HTTP.open("GET", url) do resource
|
|
open(file, "w") do file
|
|
write(file, resource)
|
|
end
|
|
@hook :post_get_attachment
|
|
end
|
|
end
|
|
file
|
|
end
|
|
|
|
function saveitems(req::Dict, libraries, currentlibrary)
|
|
@hook :pre_receive
|
|
if libraries[currentlibrary]["readonly"]
|
|
warn("Library is readonly")
|
|
return "no", Dict{String,String}("status"=> string(403))
|
|
end
|
|
|
|
parsed = JSON.parse(String(req[:data]))
|
|
|
|
foreach(i -> addtobibliography!(bibliography, i...),
|
|
parseitem.(parsed["items"]))
|
|
|
|
@hook(:after_receive,parsed)
|
|
|
|
"ok", Dict{String,String}("status"=> string(201))
|
|
end
|
|
|
|
|
|
function parseitem(item::Dict)
|
|
tp = zotero_type_map[item["itemType"]]
|
|
data = BibTeX.Citation{Symbol(tp)}()
|
|
data["author"] = authors(item["creators"])
|
|
|
|
for k in keys(item)
|
|
if k in keys(zotero_field_map)
|
|
data[zotero_field_map[k]] = item[k]
|
|
end
|
|
end
|
|
|
|
id = createcitekey(data)
|
|
filenames = getattachment.(id, item["attachments"])
|
|
data["file"] = join(filenames, "; ")
|
|
try
|
|
(id,data)
|
|
catch
|
|
warn("Type "* item["itemType"] * " does not exists!")
|
|
(nothing, nothing)
|
|
end
|
|
end
|