Skip to content
......@@ -5,7 +5,7 @@ import Sortable from 'sortablejs'
export default class extends Controller {
static targets = ['currentPage', 'articleOverlay', 'selectedArticlePanel', 'addArticleButton', 'addCompoundArticleButton', 'compoundArticlePanel']
static values = {currentPage: Number, nbpages: Number, pages: Array, articles: Array, selectedArticles: Array, issueId: String, compoundMode: Boolean}
static values = {currentPage: Number, nbPages: Number, pages: Array, articles: Array, selectedArticles: Array, issueId: String, compoundMode: Boolean}
isDragged = false
viewer = null
......@@ -18,15 +18,20 @@ export default class extends Controller {
this.selectedArticlesValue = []
if (selectedCompoundParam != null) {
const compoundParts = $(`#compound-articles-panel li[data-compound-id="${selectedCompoundParam}"]`).data('parts')
this.selectedCompound = {id: selectedCompoundParam, parts: compoundParts}
const compoundTitle = $(`#compound-articles-panel li[data-compound-id="${selectedCompoundParam}"]`).data('title')
this.selectedCompound = {id: selectedCompoundParam, parts: compoundParts, title: compoundTitle}
$(`#compound-articles-panel li[data-compound-id="${selectedCompoundParam}"]`).addClass("active")
this.load_named_entities(this.selectedCompound.parts)
} else {
this.load_named_entities([this.issueIdValue])
}
}
else {
this.selectedArticlesValue = [selectedParam]
this.load_named_entities([selectedParam])
}
this.setup_viewer()
this.load_named_entities([this.issueIdValue])
this.setup_mention_click()
this.setup_compound()
this.sortable = new Sortable(document.getElementById("compound_list"), {
......@@ -110,7 +115,7 @@ export default class extends Controller {
})
// Compound article selection
$("#compound_articles_list").on("click", "li", (event) => {
const elt = $(event.target)
const elt = $(event.currentTarget)
if(elt.hasClass("active"))
this.unselect_compound_article(elt.data('compoundId'))
else
......@@ -121,7 +126,8 @@ export default class extends Controller {
select_compound_article(compoundId) {
const compoundParts = $(`#compound-articles-panel li[data-compound-id="${compoundId}"]`).data('parts')
this.selectedCompound = {id: compoundId, parts: compoundParts}
const compoundTitle = $(`#compound-articles-panel li[data-compound-id="${compoundId}"]`).data('title')
this.selectedCompound = {id: compoundId, parts: compoundParts, title: compoundTitle}
$("#compound-articles-panel li").removeClass("active")
$(`#compound-articles-panel li[data-compound-id="${compoundId}"]`).addClass("active")
this.unselectArticles()
......@@ -163,7 +169,7 @@ export default class extends Controller {
// Go to article page and select it
let article = this.articlesValue.filter((obj) => { return obj["id"] == articleId})[0]
let pagenum = article.canvases_parts[0]
pagenum = parseInt(pagenum.substring(pagenum.lastIndexOf('_')+1, pagenum.lastIndexOf("#xywh")))
pagenum = parseInt(pagenum.substring(pagenum.lastIndexOf('/')+1, pagenum.lastIndexOf("#xywh")))
// this.viewer.goToPage(pagenum)
// this.viewer.viewport.zoomTo(2)
// this.viewer.viewport.panTo(new OpenSeadragon.Point(loc.x+loc.width/2, loc.y+loc.height/2))
......@@ -262,7 +268,7 @@ export default class extends Controller {
const art = this.articlesValue.filter(elt => elt.id == article_id)[0]
return art.all_text.replaceAll("\"", "").replaceAll("\\n", "<br/>")
}).join("\n")
$(this.selectedArticlePanelTarget).find('h5')[0].innerHTML = ""
$(this.selectedArticlePanelTarget).find('h5')[0].innerHTML = this.selectedCompound.title
$(this.selectedArticlePanelTarget).find('p')[0].innerHTML = text
}
else {
......@@ -359,7 +365,7 @@ export default class extends Controller {
$(this.addArticleButtonTarget).addClass("d-none")
const first_article_part = this.articlesValue.filter((elt)=>{return elt.id == this.selectedCompound.parts[0]})[0]
const pagenum = first_article_part.canvases_parts[0]
initialPage = parseInt(pagenum.substring(pagenum.lastIndexOf('_')+1, pagenum.lastIndexOf("#xywh")))-1
initialPage = parseInt(pagenum.substring(pagenum.lastIndexOf('/')+1, pagenum.lastIndexOf("#xywh")))-1
}
else {
initialPage = 0
......@@ -370,11 +376,11 @@ export default class extends Controller {
else {
$(this.addArticleButtonTarget).removeClass("d-none")
const pagenum = selectedArticleObject.canvases_parts[0]
initialPage = parseInt(pagenum.substring(pagenum.lastIndexOf('_')+1, pagenum.lastIndexOf("#xywh")))-1
initialPage = parseInt(pagenum.substring(pagenum.lastIndexOf('/')+1, pagenum.lastIndexOf("#xywh")))-1
}
this.viewer = OpenSeadragon({
id: "openseadragon_view",
prefixUrl: "/openseadragon/images/feathericons/",
prefixUrl: "/static/js/openseadragon/images/feathericons/",
sequenceMode: true,
initialPage: initialPage,
tileSources: this.pagesValue,
......@@ -405,7 +411,7 @@ export default class extends Controller {
this.viewer.addHandler("open", (data) => {
for (let article of this.articlesValue) {
let pagenum = article.canvases_parts[0]
pagenum = parseInt(pagenum.substring(pagenum.lastIndexOf('_')+1, pagenum.lastIndexOf("#xywh")))
pagenum = parseInt(pagenum.substring(pagenum.lastIndexOf('/')+1, pagenum.lastIndexOf("#xywh")))
if (pagenum === this.currentPageValue) {
let bbox = article.bbox
let loc = this.viewer.viewport.imageToViewportRectangle(bbox[0], bbox[1], bbox[2], bbox[3])
......
////////////////// General //////////////////
html, body {
height: 100%;
}
body .container-fluid {
height:100%;
}
#navigation {
height: 8%;
}
#main-content {
height: 92%;
}
// html, body {
// height: 100%;
// }
// body .container-fluid {
// height:100%;
// }
// #navigation {
// height: 8%;
// }
// #main-content {
// height: 92%;
// }
/////////////////////////////////////////////
////////////////// Catalog index //////////////////
......@@ -21,7 +21,7 @@ body .container-fluid {
background-color: #EEE;
}
.search_result.selected {
border: 2px solid #32a1ce;
border: 2px solid darken(hsl(180, 15%, 30%), 10%);
padding: calc(0.5em - 2px);
}
#canvas_wide_dates_histogram {
......@@ -31,11 +31,19 @@ body .container-fluid {
////////////////// Facets //////////////////
#facets .constrained {
background: lightgreen;
background: lighten(hsl(180, 15%, 30%), 45%);
}
.accordion-button:not(.collapsed) {
color: hsl(180, 15%, 30%);
}
.accordion-button:not(.collapsed)::after {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
}
li.selected_constraint {
color: green;
color: darken(hsl(180, 15%, 30%), 10%);
}
////////////////////////////////////////////
......@@ -43,9 +51,11 @@ li.selected_constraint {
#openseadragon_view {
width: auto;
height: 85vh;
border-color: hsl(180, 15%, 30%);
border-style: solid;
border-width: 2px;
background-color: #AAAAAA;
border-width: 1px;
border-radius: 6px;
background-color: #b3c3c7;
}
#viewer_container {
position: relative;
......@@ -57,11 +67,11 @@ li.selected_constraint {
#page_counter {
position: absolute;
background-color: #8AF;
background-color: #7397a0;
border-color: #000;
border-style: solid;
font-weight: bold;
border-width: 2px;
border-width: 1px;
border-radius: 6px;
top: 1vh;
right: 3.5vh;
padding: 0px 2px;
......@@ -109,66 +119,66 @@ li.selected_constraint {
///////////////////////////////////////////////
////////////////// Show Experiment /////////////////////
.tool:hover {
cursor: grab;
}
.tf-nc.tool-slot {
border-style: dashed;
width:8vw;
height:10vh;
padding: 0;
}
.tf-nc.possible-tool-slot {
border-color: cornflowerblue;
border-width: 3px;
}
.tf-nc.tool-slot-hover {
border: 1em solid blue !important;
}
// .tool:hover {
// cursor: grab;
// }
// .tf-nc.tool-slot {
// border-style: dashed;
// width:8vw;
// height:10vh;
// padding: 0;
// }
// .tf-nc.possible-tool-slot {
// border-color: cornflowerblue;
// border-width: 3px;
// }
// .tf-nc.tool-slot-hover {
// border: 1em solid blue !important;
// }
.tool-status {
height: 1em;
width: 1em;
border-radius: 50%;
border-color: black;
border-width: 1px;
border-style: solid;
display: inline-block;
}
.tool-status-created {
background-color: gray;
}
.tool-status-configured {
background-color: white;
}
.tool-status-error {
background-color: red;
}
.tool-status-running {
background-color: gold;
}
.tool-status-finished {
background-color: green;
}
// .tool-status {
// height: 1em;
// width: 1em;
// border-radius: 50%;
// border-color: black;
// border-width: 1px;
// border-style: solid;
// display: inline-block;
// }
// .tool-status-created {
// background-color: gray;
// }
// .tool-status-configured {
// background-color: white;
// }
// .tool-status-error {
// background-color: red;
// }
// .tool-status-running {
// background-color: gold;
// }
// .tool-status-finished {
// background-color: green;
// }
.tool-slot-occupied {
width:15vw;
height:15vh;
padding: 0;
}
#experiment_area {
display: flex;
align-items: center;
justify-content: center;
}
#experiment_canvas {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
overflow: visible;
}
// .tool-slot-occupied {
// width:15vw;
// height:15vh;
// padding: 0;
// }
// #experiment_area {
// display: flex;
// align-items: center;
// justify-content: center;
// }
// #experiment_canvas {
// display: flex;
// align-items: center;
// justify-content: center;
// height: 100%;
// width: 100%;
// overflow: visible;
// }
////////////////////////////////////////////////////////
////////////////////// Index Datasets ////////////////////
......@@ -182,10 +192,10 @@ li.selected_constraint {
padding: 0.5em;
}
.dataset_document:hover {
background-color: #FBFBFB;
background-color: #EEE;
}
.dataset_document.selected {
border: 2px solid #32a1ce;
border: 2px solid darken(hsl(180, 15%, 30%), 10%);
padding: calc(0.5em - 2px);
}
////////////////////////////////////////////////////////
\ No newline at end of file
import {addPrefixURL} from "../application.js"
export class DatasetAPI {
static create_dataset(title, callback) {
$.ajax({
type: "POST",
url: "/dataset/create",
data: {title: title},
url: addPrefixURL() + "/dataset/create",
data: { title: title },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -18,8 +20,8 @@ export class DatasetAPI {
static rename_dataset(id, title, callback) {
$.ajax({
type: "POST",
url: "/dataset/rename",
data: {id: id, title: title},
url: addPrefixURL() + "/dataset/rename",
data: { id: id, title: title },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -34,8 +36,8 @@ export class DatasetAPI {
static import_dataset(id, title, callback) {
$.ajax({
type: "POST",
url: "/dataset/import",
data: {original_dataset_id: id, title: title},
url: addPrefixURL() + "/dataset/import",
data: { original_dataset_id: id, title: title },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -51,8 +53,8 @@ export class DatasetAPI {
static delete_dataset(datasetId, callback) {
$.ajax({
type: "POST",
url: "/dataset/delete",
data: {dataset_id: datasetId},
url: addPrefixURL() + "/dataset/delete",
data: { dataset_id: datasetId },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -68,7 +70,7 @@ export class DatasetAPI {
static update_datasets_list(callback) {
$.ajax({
type: "GET",
url: "/datasets/update",
url: addPrefixURL() + "/datasets/update",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -85,7 +87,7 @@ export class DatasetAPI {
static setCurrentWorkingDataset(datasetId, callback) {
$.ajax({
type: "POST",
url: "/datasets/working_dataset",
url: addPrefixURL() + "/datasets/working_dataset",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -101,7 +103,7 @@ export class DatasetAPI {
static addSelectedDocumentsToWorkingDataset(documentsIds, callback) {
$.ajax({
type: "POST",
url: "/datasets/add_selected_documents",
url: addPrefixURL() + "/datasets/add_selected_documents",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -117,7 +119,7 @@ export class DatasetAPI {
static addSelectedCompoundToWorkingDataset(compoundId, callback) {
$.ajax({
type: "POST",
url: "/datasets/add_compound",
url: addPrefixURL() + "/datasets/add_compound",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -133,7 +135,7 @@ export class DatasetAPI {
static removeSelectedDocumentsToWorkingDataset(documentsIds, callback) {
$.ajax({
type: "POST",
url: "/datasets/remove_selected_documents",
url: addPrefixURL() + "/datasets/remove_selected_documents",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -149,7 +151,7 @@ export class DatasetAPI {
static addAllDocumentsToWorkingDataset(searchParams, callback) {
$.ajax({
type: "POST",
url: "/datasets/add_all_documents",
url: addPrefixURL() + "/datasets/add_all_documents",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -165,7 +167,7 @@ export class DatasetAPI {
static exportDataset(datasetId, exportType, callback) {
$.ajax({
type: "POST",
url: "/datasets/export_dataset",
url: addPrefixURL() + "/datasets/export_dataset",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -182,7 +184,7 @@ export class DatasetAPI {
static paginateDataset(datasetId, page, per_page, sort, sort_order, type, callback) {
$.ajax({
type: "POST",
url: `/dataset/${datasetId}/paginate`,
url: addPrefixURL() + `/dataset/${datasetId}/paginate`,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -199,7 +201,7 @@ export class DatasetAPI {
static getDatasets(callback) {
$.ajax({
type: "GET",
url: `/datasets/list`,
url: addPrefixURL() + "/datasets/list",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -213,7 +215,7 @@ export class DatasetAPI {
static toggleSharingStatus(dataset_id, callback) {
$.ajax({
type: "POST",
url: `/dataset/toggle_sharing_status`,
url: addPrefixURL() + "/dataset/toggle_sharing_status",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......
import {addPrefixURL} from "../application.js"
export class SearchAPI {
static load_dataset_named_entities(dataset_id, callback) {
$.ajax({
type: "POST",
url: "/dataset_named_entities",
data: {dataset_id: dataset_id},
url: addPrefixURL() + "/dataset_named_entities",
data: { dataset_id: dataset_id },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -20,8 +22,8 @@ export class SearchAPI {
static load_named_entities(docs_ids, callback) {
$.ajax({
type: "POST",
url: "/named_entities",
data: {docs_ids: docs_ids},
url: addPrefixURL() + "/named_entities",
data: { docs_ids: docs_ids },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -37,8 +39,8 @@ export class SearchAPI {
static facetPagination(fieldName, nbPages, currentPage, callback) {
$.ajax({
type: "POST",
url: "/catalog/facet_pagination",
data: {field_name: fieldName, nb_pages: nbPages, current_page: currentPage},
url: addPrefixURL() + "/catalog/facet_pagination",
data: { field_name: fieldName, nb_pages: nbPages, current_page: currentPage },
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -54,7 +56,7 @@ export class SearchAPI {
static wideDatesHistogram(callback) {
$.ajax({
type: "POST",
url: "/catalog/wide_dates_histogram",
url: addPrefixURL() + "/catalog/wide_dates_histogram",
data: {},
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
......@@ -71,7 +73,7 @@ export class SearchAPI {
static confirm_compond_creation(article_parts, callback) {
$.ajax({
type: "POST",
url: `/catalog/confirm_compound_creation`,
url: addPrefixURL() + "/catalog/confirm_compound_creation",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -87,7 +89,7 @@ export class SearchAPI {
static create_compound(title, all_text, issue_id, article_parts_ids, callback) {
$.ajax({
type: "POST",
url: `/catalog/create_compound`,
url: addPrefixURL() + "/catalog/create_compound",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -106,7 +108,7 @@ export class SearchAPI {
static delete_compound_article(compound_id, callback) {
$.ajax({
type: "POST",
url: `/catalog/delete_compound`,
url: addPrefixURL() + "/catalog/delete_compound",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......@@ -122,7 +124,7 @@ export class SearchAPI {
static random_sample(callback) {
$.ajax({
type: "POST",
url: `/catalog/random_sample`,
url: addPrefixURL() + "/catalog/random_sample",
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
......
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
layout 'mailer'
default from: "from@example.com"
layout "mailer"
end
class Article
attr_accessor :id, :title, :all_text, :date_created, :language, :canvases_parts, :newspaper, :issue_id, :thumbnail_url, :bbox
attr_accessor :id, :title, :all_text, :date_created, :language, :canvases_parts, :newspaper, :issue_id, :thumbnail_url, :bbox
def self.from_solr(id)
solr_doc = SolrSearcher.get_doc_by_id id
Article.from_solr_doc solr_doc
end
def self.from_solr id
solr_doc = SolrSearcher.get_doc_by_id id
Article.from_solr_doc solr_doc
end
def self.from_solr_doc(solr_doc)
a = Article.new
a.id = solr_doc["id"]
a.title = solr_doc["title_ssi"]
a.language = solr_doc["language_ssi"]
a.all_text = solr_doc["all_text_t#{a.language}_siv"]
a.date_created = solr_doc["date_created_ssi"]
a.issue_id = solr_doc["from_issue_ssi"]
a.newspaper = solr_doc["member_of_collection_ids_ssim"].first
a.thumbnail_url = solr_doc["thumbnail_url_ss"]
a.canvases_parts = solr_doc["canvases_parts_ssm"]
a.bbox = a.get_location
a
end
def self.from_solr_doc solr_doc
a = Article.new
a.id = solr_doc['id']
a.title = solr_doc['title_ssi']
a.language = solr_doc['language_ssi']
a.all_text = solr_doc["all_text_t#{a.language}_siv"]
a.date_created = solr_doc['date_created_ssi']
a.issue_id = solr_doc['from_issue_ssi']
a.newspaper = solr_doc['member_of_collection_ids_ssim'].first
a.thumbnail_url = solr_doc['thumbnail_url_ss']
a.canvases_parts = solr_doc['canvases_parts_ssm']
a.bbox = a.get_location
a
end
def to_solr(page_iiif_url)
solr_doc = {}
solr_doc["id"] = self.id
solr_doc["title_ssi"] = self.title
solr_doc["language_ssi"] = self.language
solr_doc["all_text_t#{self.language}_siv"] = self.all_text
solr_doc["all_text_unstemmed_t#{self.language}_siv"] = self.all_text
solr_doc["date_created_ssi"] = self.date_created
solr_doc["date_created_dtsi"] = DateTime.parse(self.date_created).strftime("%Y-%m-%dT%H:%M:%SZ")
solr_doc["year_isi"] = solr_doc["date_created_ssi"][0..3].to_i
d = DateTime.parse solr_doc["date_created_dtsi"]
solr_doc["month_isi"] = d.month
solr_doc["day_isi"] = d.wday
solr_doc["from_issue_ssi"] = self.issue_id
solr_doc["member_of_collection_ids_ssim"] = self.newspaper
solr_doc["canvases_parts_ssm"] = self.canvases_parts
solr_doc["thumbnail_url_ss"] = self.get_iiif_url(page_iiif_url)
solr_doc["has_model_ssim"] = "Article"
solr_doc
end
def to_solr(page_iiif_url)
solr_doc = {}
solr_doc['id'] = self.id
solr_doc['title_ssi'] = self.title
solr_doc["language_ssi"] = self.language
solr_doc["all_text_t#{self.language}_siv"] = self.all_text
solr_doc["all_text_unstemmed_t#{self.language}_siv"] = self.all_text
solr_doc['date_created_ssi'] = self.date_created
solr_doc['date_created_dtsi'] = DateTime.parse(self.date_created).strftime('%Y-%m-%dT%H:%M:%SZ')
solr_doc['year_isi'] = solr_doc['date_created_ssi'][0..3].to_i
d = DateTime.parse solr_doc["date_created_dtsi"]
solr_doc['month_isi'] = d.month
solr_doc['day_isi'] = d.wday
solr_doc['from_issue_ssi'] = self.issue_id
solr_doc['member_of_collection_ids_ssim'] = self.newspaper
solr_doc['canvases_parts_ssm'] = self.canvases_parts
solr_doc['thumbnail_url_ss'] = self.get_iiif_url(page_iiif_url)
solr_doc['has_model_ssim'] = 'Article'
solr_doc
def get_thumbnail
if Rails.configuration.iiif_sources[:local].include? self.newspaper
pagenum = self.canvases_parts[0][self.canvases_parts[0].rindex("_") + 1...self.canvases_parts[0].rindex("#")].to_i
self.get_iiif_url("https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.issue_id}_page_#{pagenum}.ptif")
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
self.thumbnail_url
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
self.thumbnail_url
end
end
def get_thumbnail
if Rails.configuration.iiif_sources[:local].include? self.newspaper
pagenum = self.canvases_parts[0][self.canvases_parts[0].rindex('_')+1...self.canvases_parts[0].rindex('#')].to_i
self.get_iiif_url("https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.issue_id}_page_#{pagenum}.ptif")
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
self.thumbnail_url
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
self.thumbnail_url
end
end
def get_location
coords = self.canvases_parts.map { |c| c[c.rindex("#xywh=") + 6..-1].split(",").map(&:to_i) }
min_x = coords.map { |coord| coord[0] }.min
max_x = coords.map { |coord| coord[0] + coord[2] }.max
min_y = coords.map { |coord| coord[1] }.min
max_y = coords.map { |coord| coord[1] + coord[3] }.max
canvas_coords = [min_x, max_x, min_y, max_y]
canvas_size = [canvas_coords[1] - canvas_coords[0], canvas_coords[3] - canvas_coords[2]]
[min_x, min_y, canvas_size[0], canvas_size[1]]
end
def get_location
coords = self.canvases_parts.map { |c| c[c.rindex('#xywh=')+6..-1].split(',').map(&:to_i) }
min_x = coords.map{ |coord| coord[0] }.min
max_x = coords.map{ |coord| coord[0] + coord[2] }.max
min_y = coords.map{ |coord| coord[1] }.min
max_y = coords.map{ |coord| coord[1] + coord[3] }.max
canvas_coords = [min_x, max_x, min_y, max_y]
canvas_size = [canvas_coords[1]-canvas_coords[0], canvas_coords[3]-canvas_coords[2]]
[min_x,min_y,canvas_size[0],canvas_size[1]]
end
def get_iiif_url(page_iiif_url)
canvas_url = self.canvases_parts[0]
coords = self.canvases_parts.map { |c| c[c.rindex("#xywh=") + 6..-1].split(",").map(&:to_i) }
min_x = coords.map { |coord| coord[0] }.min
max_x = coords.map { |coord| coord[0] + coord[2] }.max
min_y = coords.map { |coord| coord[1] }.min
max_y = coords.map { |coord| coord[1] + coord[3] }.max
pagenum = canvas_url[canvas_url.rindex("_") + 1...canvas_url.rindex("#")].to_i
"#{page_iiif_url}/#{min_x},#{min_y},#{max_x - min_x},#{max_y - min_y}/full/0/default.jpg"
end
def get_iiif_url(page_iiif_url)
canvas_url = self.canvases_parts[0]
coords = self.canvases_parts.map { |c| c[c.rindex('#xywh=')+6..-1].split(',').map(&:to_i) }
min_x = coords.map{ |coord| coord[0] }.min
max_x = coords.map{ |coord| coord[0] + coord[2] }.max
min_y = coords.map{ |coord| coord[1] }.min
max_y = coords.map{ |coord| coord[1] + coord[3] }.max
pagenum = canvas_url[canvas_url.rindex('_')+1...canvas_url.rindex('#')].to_i
"#{page_iiif_url}/#{min_x},#{min_y},#{max_x-min_x},#{max_y-min_y}/full/0/default.jpg"
def self.named_entities(article_id)
nems = SolrSearcher.query({ q: "article_id_ssi:#{article_id}", rows: 1000000 })["response"]["docs"]
output = { LOC: {}, PER: {}, ORG: {}, HumanProd: {} }
nems.select { |ne_solr| ne_solr["type_ssi"] == "LOC" }.each do |ne_solr|
output[:LOC][ne_solr["linked_entity_ssi"]] = [] unless output[:LOC].has_key? ne_solr["linked_entity_ssi"]
output[:LOC][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
def self.named_entities(article_id)
nems = SolrSearcher.query({q:"article_id_ssi:#{article_id}", rows: 1000000})['response']['docs']
output = {LOC: {}, PER: {}, ORG: {}, HumanProd: {}}
nems.select {|ne_solr| ne_solr['type_ssi'] == "LOC"}.each do |ne_solr|
output[:LOC][ne_solr['linked_entity_ssi']] = [] unless output[:LOC].has_key? ne_solr['linked_entity_ssi']
output[:LOC][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "PER"}.each do |ne_solr|
output[:PER][ne_solr['linked_entity_ssi']] = [] unless output[:PER].has_key? ne_solr['linked_entity_ssi']
output[:PER][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "ORG"}.each do |ne_solr|
output[:ORG][ne_solr['linked_entity_ssi']] = [] unless output[:ORG].has_key? ne_solr['linked_entity_ssi']
output[:ORG][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "HumanProd"}.each do |ne_solr|
output[:HumanProd][ne_solr['linked_entity_ssi']] = [] unless output[:HumanProd].has_key? ne_solr['linked_entity_ssi']
output[:HumanProd][ne_solr['linked_entity_ssi']].append(ne_solr)
end
output
nems.select { |ne_solr| ne_solr["type_ssi"] == "PER" }.each do |ne_solr|
output[:PER][ne_solr["linked_entity_ssi"]] = [] unless output[:PER].has_key? ne_solr["linked_entity_ssi"]
output[:PER][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "ORG" }.each do |ne_solr|
output[:ORG][ne_solr["linked_entity_ssi"]] = [] unless output[:ORG].has_key? ne_solr["linked_entity_ssi"]
output[:ORG][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "HumanProd" }.each do |ne_solr|
output[:HumanProd][ne_solr["linked_entity_ssi"]] = [] unless output[:HumanProd].has_key? ne_solr["linked_entity_ssi"]
output[:HumanProd][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
end
\ No newline at end of file
output
end
end
class CompoundArticle < ActiveRecord::Base
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
end
\ No newline at end of file
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
end
module AbstractSearcher
extend ActiveSupport::Concern
extend ActiveSupport::Concern
def self.query
raise NotImplementedError, "Subclasses must define `query`."
end
def self.query
raise NotImplementedError, "Subclasses must define `query`."
end
def self.get_doc_by_id(id)
raise NotImplementedError, "Subclasses must define `get_doc_by_id`."
end
end
\ No newline at end of file
def self.get_doc_by_id(id)
raise NotImplementedError, "Subclasses must define `get_doc_by_id`."
end
end
class Current < ActiveSupport::CurrentAttributes
attribute :user
end
class Dataset < ActiveRecord::Base
# after_find :nb_issues, :nb_articles
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
# after_find :nb_issues, :nb_articles
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
def add_documents(documents_ids)
existing = []
documents_ids.each do |doc_id|
if self.documents.any?{ |doc| doc['id'] == doc_id }
existing << doc_id
else
doc_type = doc_id.index("_article_").nil? ? "issue" : "article"
self.documents << {id: doc_id, type: doc_type}
end
end
self.save
return existing
end
def add_compound(compound_id)
existing = []
if self.documents.any?{ |doc| doc['id'] == compound_id }
existing << compound_id
else
doc_type = "compound"
self.documents << {id: compound_id, type: doc_type}
end
self.save
return existing
def add_documents(documents_ids)
existing = []
documents_ids.each do |doc_id|
if self.documents.any? { |doc| doc["id"] == doc_id }
existing << doc_id
else
doc_type = doc_id.index("_article_").nil? ? "issue" : "article"
self.documents << { id: doc_id, type: doc_type }
end
end
self.save
return existing
end
def remove_documents(documents_ids)
self.documents.delete_if{ |elt| documents_ids.include? elt['id'] }
self.save
def add_compound(compound_id)
existing = []
if self.documents.any? { |doc| doc["id"] == compound_id }
existing << compound_id
else
doc_type = "compound"
self.documents << { id: compound_id, type: doc_type }
end
self.save
return existing
end
def contains doc_id
self.documents.index { |doc| doc['id'] == doc_id }.nil? ? false : true
end
def remove_documents(documents_ids)
self.documents.delete_if { |elt| documents_ids.include? elt["id"] }
self.save
end
def nb_issues
self.documents.select do |doc|
doc['type'] == 'issue'
end.size
end
def contains(doc_id)
self.documents.index { |doc| doc["id"] == doc_id }.nil? ? false : true
end
def nb_articles
self.documents.select do |doc|
doc['type'] == 'article'
end.size
end
def nb_issues
self.documents.select do |doc|
doc["type"] == "issue"
end.size
end
def nb_compound_articles
self.documents.select do |doc|
doc['type'] == 'compound'
end.size
end
def nb_articles
self.documents.select do |doc|
doc["type"] == "article"
end.size
end
def fetch_paginated_documents(page, per_page, sort, sort_order, type, recursive=false)
docs = self.documents.select {|doc| type == "all" || doc['type'] == type }
def nb_compound_articles
self.documents.select do |doc|
doc["type"] == "compound"
end.size
end
nb_pages = (docs.size / per_page.to_f).ceil
nb_pages = 1 if nb_pages == 0
sort = (sort == "default") ? "score" : sort
solr_docs = nil
def fetch_paginated_documents(page, per_page, sort, sort_order, type, recursive = false)
docs = self.documents.select { |doc| type == "all" || doc["type"] == type }
compounds_ids = docs.select{|d| d['type'] == "compound" }.map{ |d| d['id'] }
compound_articles = CompoundArticle.find(compounds_ids)
nb_pages = (docs.size / per_page.to_f).ceil
nb_pages = 1 if nb_pages == 0
sort = (sort == "default") ? "score" : sort
solr_docs = nil
compounds_ids = docs.select { |d| d["type"] == "compound" }.map { |d| d["id"] }
compound_articles = CompoundArticle.find(compounds_ids)
solr_ids = docs.select{|d| d['type'] != "compound" }.map{ |d| d['id'] }
unless solr_ids.empty?
solr_docs = SolrSearcher.query({
solr_ids = docs.select { |d| d["type"] != "compound" }.map { |d| d["id"] }
unless solr_ids.empty?
solr_docs = SolrSearcher.query({
q: "*:*",
fq: "id:(#{solr_ids.join(' ')})",
fq: "id:(#{solr_ids.join(" ")})",
rows: per_page,
sort: "#{sort} #{sort_order}",
start: (page-1)*per_page
})['response']['docs']
solr_docs.map! do |solr_doc|
if solr_doc['id'].index("_article_").nil?
Issue.from_solr_doc solr_doc
else
Article.from_solr_doc solr_doc
end
end
end
if recursive and page < nb_pages and !solr_docs.nil?
solr_docs = solr_docs.concat fetch_paginated_documents(page+1, per_page, sort, sort_order, type, true)[:docs]
start: (page - 1) * per_page,
})["response"]["docs"]
solr_docs.map! do |solr_doc|
if solr_doc["id"].index("_article_").nil?
Issue.from_solr_doc solr_doc
else
Article.from_solr_doc solr_doc
end
return {docs: solr_docs.nil? ? compound_articles : solr_docs+compound_articles, nb_pages: nb_pages}
end
end
if recursive and page < nb_pages and !solr_docs.nil?
solr_docs = solr_docs.concat fetch_paginated_documents(page + 1, per_page, sort, sort_order, type, true)[:docs]
end
return { docs: solr_docs.nil? ? compound_articles : solr_docs + compound_articles, nb_pages: nb_pages }
end
def named_entities
article_ids = self.documents.select {|d| d['type'] == 'article' }.map{|d| d['id']}
issue_ids = self.documents.select {|d| d['type'] == 'issue' }.map{|d| d['id']}
parts_ids = self.documents.select {|d| d['type'] == 'compound' }.map{|d| CompoundArticle.find(d['id']).parts}.flatten.uniq
nems = []
nems = SolrSearcher.query({q: "*:*", fq: "article_id_ssi:(#{article_ids.join(' OR ')})", rows: 1000000})['response']['docs'] unless article_ids.empty?
nems += SolrSearcher.query({q: "*:*", fq: "article_id_ssi:(#{parts_ids.join(' OR ')})", rows: 1000000})['response']['docs'] unless parts_ids.empty?
nems += SolrSearcher.query({q: "*:*", fq: "issue_id_ssi:(#{issue_ids.join(' OR ')})", rows: 1000000})['response']['docs'] unless issue_ids.empty?
output = {LOC: {}, PER: {}, ORG: {}, HumanProd: {}}
nems.select {|ne_solr| ne_solr['type_ssi'] == "LOC"}.each do |ne_solr|
output[:LOC][ne_solr['linked_entity_ssi']] = [] unless output[:LOC].has_key? ne_solr['linked_entity_ssi']
output[:LOC][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "PER"}.each do |ne_solr|
output[:PER][ne_solr['linked_entity_ssi']] = [] unless output[:PER].has_key? ne_solr['linked_entity_ssi']
output[:PER][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "ORG"}.each do |ne_solr|
output[:ORG][ne_solr['linked_entity_ssi']] = [] unless output[:ORG].has_key? ne_solr['linked_entity_ssi']
output[:ORG][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "HumanProd"}.each do |ne_solr|
output[:HumanProd][ne_solr['linked_entity_ssi']] = [] unless output[:HumanProd].has_key? ne_solr['linked_entity_ssi']
output[:HumanProd][ne_solr['linked_entity_ssi']].append(ne_solr)
end
output
def named_entities
article_ids = self.documents.select { |d| d["type"] == "article" }.map { |d| d["id"] }
issue_ids = self.documents.select { |d| d["type"] == "issue" }.map { |d| d["id"] }
parts_ids = self.documents.select { |d| d["type"] == "compound" }.map { |d| CompoundArticle.find(d["id"]).parts }.flatten.uniq
nems = []
nems = SolrSearcher.query({ q: "*:*", fq: "article_id_ssi:(#{article_ids.join(" OR ")})", rows: 1000000 })["response"]["docs"] unless article_ids.empty?
nems += SolrSearcher.query({ q: "*:*", fq: "article_id_ssi:(#{parts_ids.join(" OR ")})", rows: 1000000 })["response"]["docs"] unless parts_ids.empty?
nems += SolrSearcher.query({ q: "*:*", fq: "issue_id_ssi:(#{issue_ids.join(" OR ")})", rows: 1000000 })["response"]["docs"] unless issue_ids.empty?
output = { LOC: {}, PER: {}, ORG: {}, HumanProd: {} }
nems.select { |ne_solr| ne_solr["type_ssi"] == "LOC" }.each do |ne_solr|
output[:LOC][ne_solr["linked_entity_ssi"]] = [] unless output[:LOC].has_key? ne_solr["linked_entity_ssi"]
output[:LOC][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "PER" }.each do |ne_solr|
output[:PER][ne_solr["linked_entity_ssi"]] = [] unless output[:PER].has_key? ne_solr["linked_entity_ssi"]
output[:PER][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "ORG" }.each do |ne_solr|
output[:ORG][ne_solr["linked_entity_ssi"]] = [] unless output[:ORG].has_key? ne_solr["linked_entity_ssi"]
output[:ORG][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "HumanProd" }.each do |ne_solr|
output[:HumanProd][ne_solr["linked_entity_ssi"]] = [] unless output[:HumanProd].has_key? ne_solr["linked_entity_ssi"]
output[:HumanProd][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
output
end
end
class Experiment < ActiveRecord::Base
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
belongs_to :user, optional: false
validates :title, length: { minimum: 1 }
def add_tool(parent_id, tool)
if parent_id != 0
self.locate_tool(self.description, parent_id) do |t|
t['children'] << tool.to_h
end
else
self.description['children'] << tool.to_h
end
def add_tool(parent_id, tool)
if parent_id != 0
self.locate_tool(self.description, parent_id) do |t|
t["children"] << tool.to_h
end
else
self.description["children"] << tool.to_h
end
end
def delete_tool(tool_id)
ids = detach_tool(self.description, nil, tool_id)
end
def delete_tool(tool_id)
ids = detach_tool(self.description, nil, tool_id)
end
def load_tools
ids = gather_ids self.description
Tool.where(id: ids).pluck(:id, :status, :tool_type, :input_type, :output_type, :parent_id).map do |t|
[t[0], {id: t[0], status: t[1], type: t[2], input_type: t[3], output_type: t[4], parent_id: t[5]}]
end.to_h
end
def load_tools
ids = gather_ids self.description
Tool.where(id: ids).pluck(:id, :status, :tool_type, :input_type, :output_type, :parent_id).map do |t|
[t[0], { id: t[0], status: t[1], type: t[2], input_type: t[3], output_type: t[4], parent_id: t[5] }]
end.to_h
end
def finished?
tools = self.load_tools
tools.values.all? { |t| t[:status] == "finished" }
end
def finished?
tools = self.load_tools
tools.values.all? { |t| t[:status] == "finished" }
end
def running?
tools = self.load_tools
tools.values.any? { |t| t[:status] == "running" }
end
def running?
tools = self.load_tools
tools.values.any? { |t| t[:status] == "running" }
end
def get_tool_ids
gather_ids self.description
end
def get_tool_ids
gather_ids self.description
end
def continue_from(tool_id)
locate_tool(self.description, tool_id) do |t|
tools_to_start = t['children'].map { |c| c['tool']['id'] }
tools_to_start.each do |tool_id|
tool = Tool.find(tool_id)
tool.run(true) if tool.runnable?
end
end
def continue_from(tool_id)
locate_tool(self.description, tool_id) do |t|
tools_to_start = t["children"].map { |c| c["tool"]["id"] }
tools_to_start.each do |tool_id|
tool = Tool.find(tool_id)
tool.run(true) if tool.runnable?
end
end
end
private
private
def locate_tool(tree_part, tool_id, &block)
if tree_part.has_key?('tool')
if tree_part['tool']['id'] == tool_id
yield tree_part
return true
else
tree_part['children'].each do |subtree|
return true if locate_tool(subtree, tool_id, &block)
end
end
else
if tree_part['children'].empty?
yield tree_part
end
tree_part['children'].each do |subtree|
return true if locate_tool(subtree, tool_id, &block)
end
def locate_tool(tree_part, tool_id, &block)
if tree_part.has_key?("tool")
if tree_part["tool"]["id"] == tool_id
yield tree_part
return true
else
tree_part["children"].each do |subtree|
return true if locate_tool(subtree, tool_id, &block)
end
false
end
else
if tree_part["children"].empty?
yield tree_part
end
tree_part["children"].each do |subtree|
return true if locate_tool(subtree, tool_id, &block)
end
end
false
end
def detach_tool(tree, parent_array, tool_id, &block)
if tree.has_key?('tool')
if tree['tool']['id'] == tool_id
ids = gather_ids(tree)
parent_array.delete(tree) unless parent_array.nil?
return ids
else
tree['children'].each do |subtree|
res = detach_tool(subtree, tree['children'], tool_id, &block)
return res unless res.nil?
end
end
else
tree['children'].each do |subtree|
res = detach_tool(subtree, tree['children'], tool_id, &block)
return res unless res.nil?
end
def detach_tool(tree, parent_array, tool_id, &block)
if tree.has_key?("tool")
if tree["tool"]["id"] == tool_id
ids = gather_ids(tree)
parent_array.delete(tree) unless parent_array.nil?
return ids
else
tree["children"].each do |subtree|
res = detach_tool(subtree, tree["children"], tool_id, &block)
return res unless res.nil?
end
nil
end
else
tree["children"].each do |subtree|
res = detach_tool(subtree, tree["children"], tool_id, &block)
return res unless res.nil?
end
end
nil
end
def gather_ids(tree, ids=[])
tree['children'].each do |subtree|
ids.concat(gather_ids(subtree))
end
if tree.has_key?('tool')
ids << tree['tool']['id']
end
return ids
def gather_ids(tree, ids = [])
tree["children"].each do |subtree|
ids.concat(gather_ids(subtree))
end
if tree.has_key?("tool")
ids << tree["tool"]["id"]
end
return ids
end
end
class Issue
attr_accessor :id, :title, :date_created, :language, :original_uri, :nb_pages, :all_text, :thumbnail_url, :newspaper, :pages, :articles
attr_accessor :id, :title, :date_created, :language, :original_uri, :nb_pages, :all_text, :thumbnail_url, :newspaper, :pages, :articles
def self.from_solr(id, with_pages = false, with_articles = false)
solr_doc = SolrSearcher.get_doc_by_id id
Issue.from_solr_doc(solr_doc, with_pages, with_articles)
end
def self.from_solr(id, with_pages=false, with_articles=false)
solr_doc = SolrSearcher.get_doc_by_id id
Issue.from_solr_doc(solr_doc, with_pages, with_articles)
def self.from_solr_doc(solr_doc, with_pages = false, with_articles = false)
i = Issue.new
i.id = solr_doc["id"]
i.language = solr_doc["language_ssi"]
i.newspaper = solr_doc["member_of_collection_ids_ssim"][0]
i.title = solr_doc["title_ssi"]
i.date_created = solr_doc["date_created_ssi"]
i.original_uri = solr_doc["original_uri_ss"]
i.nb_pages = solr_doc["member_ids_ssim"].size
i.thumbnail_url = solr_doc["thumbnail_url_ss"]
i.all_text = solr_doc["all_text_t#{i.language}_siv"]
if with_pages
i.pages = []
solr_doc["member_ids_ssim"].each do |pageid|
i.pages << Page.from_solr(pageid)
end
end
def self.from_solr_doc(solr_doc, with_pages=false, with_articles=false)
i = Issue.new
i.id = solr_doc['id']
i.language = solr_doc['language_ssi']
i.newspaper = solr_doc['member_of_collection_ids_ssim'][0]
i.title = solr_doc['title_ssi']
i.date_created = solr_doc['date_created_ssi']
i.original_uri = solr_doc['original_uri_ss']
i.nb_pages = solr_doc['member_ids_ssim'].size
i.thumbnail_url = solr_doc['thumbnail_url_ss']
i.all_text = solr_doc["all_text_t#{i.language}_siv"]
if with_pages
i.pages = []
solr_doc['member_ids_ssim'].each do |pageid|
i.pages << Page.from_solr(pageid)
end
end
if with_articles
i.articles = []
articles_docs = SolrSearcher.query({q: "*:*", fq: ["from_issue_ssi:#{i.id}", "has_model_ssim:Article"], fl:"*", rows:10000})['response']['docs']
articles_docs.each do |articles_doc|
i.articles << Article.from_solr_doc(articles_doc)
end
end
i
if with_articles
i.articles = []
articles_docs = SolrSearcher.query({ q: "*:*", fq: ["from_issue_ssi:#{i.id}", "has_model_ssim:Article"], fl: "*", rows: 10000 })["response"]["docs"]
articles_docs.each do |articles_doc|
i.articles << Article.from_solr_doc(articles_doc)
end
end
i
end
def to_solr
solr_doc = {}
solr_doc['id'] = self.id
solr_doc['has_model_ssim'] = 'Issue'
solr_doc['title_ssi'] = self.title
solr_doc['date_created_ssi'] = self.date_created
solr_doc['date_created_dtsi'] = DateTime.parse(self.date_created).strftime('%Y-%m-%dT%H:%M:%SZ')
solr_doc['language_ssi'] = self.language
solr_doc['original_uri_ss'] = self.original_uri
solr_doc['nb_pages_isi'] = self.nb_pages
solr_doc['thumbnail_url_ss'] = self.thumbnail_url
solr_doc['member_ids_ssim'] = self.pages.map(&:id)
solr_doc['year_isi'] = solr_doc['date_created_ssi'][0..3].to_i
d = DateTime.parse solr_doc["date_created_dtsi"]
solr_doc['month_isi'] = d.month
solr_doc['day_isi'] = d.wday
solr_doc["member_of_collection_ids_ssim"] = self.newspaper
solr_doc["all_text_t#{self.language}_siv"] = self.all_text
solr_doc["all_text_unstemmed_t#{self.language}_siv"] = self.all_text
solr_doc
end
def to_solr
solr_doc = {}
solr_doc["id"] = self.id
solr_doc["has_model_ssim"] = "Issue"
solr_doc["title_ssi"] = self.title
solr_doc["date_created_ssi"] = self.date_created
solr_doc["date_created_dtsi"] = DateTime.parse(self.date_created).strftime("%Y-%m-%dT%H:%M:%SZ")
solr_doc["language_ssi"] = self.language
solr_doc["original_uri_ss"] = self.original_uri
solr_doc["nb_pages_isi"] = self.nb_pages
solr_doc["thumbnail_url_ss"] = self.thumbnail_url
solr_doc["member_ids_ssim"] = self.pages.map(&:id)
solr_doc["year_isi"] = solr_doc["date_created_ssi"][0..3].to_i
d = DateTime.parse solr_doc["date_created_dtsi"]
solr_doc["month_isi"] = d.month
solr_doc["day_isi"] = d.wday
solr_doc["member_of_collection_ids_ssim"] = self.newspaper
solr_doc["all_text_t#{self.language}_siv"] = self.all_text
solr_doc["all_text_unstemmed_t#{self.language}_siv"] = self.all_text
solr_doc
end
def get_thumbnail
if Rails.configuration.iiif_sources[:local].include? self.newspaper
"https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.id}_page_1.ptif/full/200,/0/default.jpg"
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
iiif_pages = self.pages.map{ |p| "#{p.iiif_url}/info.json" } # to change
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
iiif_pages = self.pages.map{ |p| "#{p.iiif_url}/info.json" } # to change
end
def get_thumbnail
if Rails.configuration.iiif_sources[:local].include? self.newspaper
"https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.id}_page_1.ptif/full/200,/0/default.jpg"
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
iiif_pages = self.pages.map { |p| "#{p.iiif_url}/info.json" } # to change
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
iiif_pages = self.pages.map { |p| "#{p.iiif_url}/info.json" } # to change
end
end
def get_iiif_urls
if Rails.configuration.iiif_sources[:local].include? self.newspaper
iiif_pages = self.pages.map do |p|
"https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.id}_page_#{p.page_number}.ptif/info.json"
end
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
iiif_pages = self.pages.map{ |p| "#{p.iiif_url}/info.json" }
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
iiif_pages = self.pages.map{ |p| "#{p.iiif_url}/info.json" }
end
iiif_pages
def get_iiif_urls
if Rails.configuration.iiif_sources[:local].include? self.newspaper
iiif_pages = self.pages.map do |p|
"https://iiif.newseye.eu/iiif/#{self.newspaper}/#{self.id}_page_#{p.page_number}.ptif/info.json"
end
elsif Rails.configuration.iiif_sources[:external].include? self.newspaper
iiif_pages = self.pages.map { |p| "#{p.iiif_url}/info.json" }
elsif Rails.configuration.iiif_sources[:external_onb].include? self.newspaper
iiif_pages = self.pages.map { |p| "#{p.iiif_url}/info.json" }
end
iiif_pages
end
def self.named_entities(issue_id)
nems = SolrSearcher.query({q:"issue_id_ssi:#{issue_id}", rows: 1000000})['response']['docs']
output = {LOC: {}, PER: {}, ORG: {}, HumanProd: {}}
nems.select {|ne_solr| ne_solr['type_ssi'] == "LOC"}.each do |ne_solr|
output[:LOC][ne_solr['linked_entity_ssi']] = [] unless output[:LOC].has_key? ne_solr['linked_entity_ssi']
output[:LOC][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "PER"}.each do |ne_solr|
output[:PER][ne_solr['linked_entity_ssi']] = [] unless output[:PER].has_key? ne_solr['linked_entity_ssi']
output[:PER][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "ORG"}.each do |ne_solr|
output[:ORG][ne_solr['linked_entity_ssi']] = [] unless output[:ORG].has_key? ne_solr['linked_entity_ssi']
output[:ORG][ne_solr['linked_entity_ssi']].append(ne_solr)
end
nems.select {|ne_solr| ne_solr['type_ssi'] == "HumanProd"}.each do |ne_solr|
output[:HumanProd][ne_solr['linked_entity_ssi']] = [] unless output[:HumanProd].has_key? ne_solr['linked_entity_ssi']
output[:HumanProd][ne_solr['linked_entity_ssi']].append(ne_solr)
end
output
def self.named_entities(issue_id)
nems = SolrSearcher.query({ q: "issue_id_ssi:#{issue_id}", rows: 1000000 })["response"]["docs"]
output = { LOC: {}, PER: {}, ORG: {}, HumanProd: {} }
nems.select { |ne_solr| ne_solr["type_ssi"] == "LOC" }.each do |ne_solr|
output[:LOC][ne_solr["linked_entity_ssi"]] = [] unless output[:LOC].has_key? ne_solr["linked_entity_ssi"]
output[:LOC][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "PER" }.each do |ne_solr|
output[:PER][ne_solr["linked_entity_ssi"]] = [] unless output[:PER].has_key? ne_solr["linked_entity_ssi"]
output[:PER][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "ORG" }.each do |ne_solr|
output[:ORG][ne_solr["linked_entity_ssi"]] = [] unless output[:ORG].has_key? ne_solr["linked_entity_ssi"]
output[:ORG][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
nems.select { |ne_solr| ne_solr["type_ssi"] == "HumanProd" }.each do |ne_solr|
output[:HumanProd][ne_solr["linked_entity_ssi"]] = [] unless output[:HumanProd].has_key? ne_solr["linked_entity_ssi"]
output[:HumanProd][ne_solr["linked_entity_ssi"]].append(ne_solr)
end
end
\ No newline at end of file
output
end
end
class Notification < ActiveRecord::Base
belongs_to :user, optional: false
end
\ No newline at end of file
belongs_to :user, optional: false
end
class Page
attr_accessor :id, :page_number, :width, :height, :mime_type, :iiif_url, :ocr_path, :image_path
attr_accessor :id, :page_number, :width, :height, :mime_type, :iiif_url, :ocr_path, :image_path
def self.from_solr(id)
attrs = SolrSearcher.get_doc_by_id id
p = Page.new
p.id = attrs["id"]
p.page_number = attrs["page_number_isi"]
p.width = attrs["width_isi"]
p.height = attrs["height_isi"]
p.mime_type = attrs["mime_type_ssi"]
p.iiif_url = attrs["iiif_url_ss"]
p.ocr_path = attrs["ocr_path_ss"]
p.image_path = attrs["image_path_ss"] if attrs["image_path_ss"]
p
end
def self.from_solr id
attrs = SolrSearcher.get_doc_by_id id
p = Page.new
p.id = attrs['id']
p.page_number = attrs['page_number_isi']
p.width = attrs['width_isi']
p.height = attrs['height_isi']
p.mime_type = attrs['mime_type_ssi']
p.iiif_url = attrs['iiif_url_ss']
p.ocr_path = attrs['ocr_path_ss']
p.image_path = attrs['image_path_ss'] if attrs['image_path_ss']
p
end
def to_solr
solr_doc = {}
solr_doc['id'] = self.id
solr_doc['has_model_ssim'] = 'PageFileSet'
solr_doc['page_number_isi'] = self.page_number
solr_doc['width_isi'] = self.width
solr_doc['height_isi'] = self.height
solr_doc['mime_type_ssi'] = self.mime_type
solr_doc['iiif_url_ss'] = self.iiif_url
solr_doc['ocr_path_ss'] = self.ocr_path
solr_doc
end
end
\ No newline at end of file
def to_solr
solr_doc = {}
solr_doc["id"] = self.id
solr_doc["has_model_ssim"] = "PageFileSet"
solr_doc["page_number_isi"] = self.page_number
solr_doc["width_isi"] = self.width
solr_doc["height_isi"] = self.height
solr_doc["mime_type_ssi"] = self.mime_type
solr_doc["iiif_url_ss"] = self.iiif_url
solr_doc["ocr_path_ss"] = self.ocr_path
solr_doc
end
end
class SolrQuery
attr_accessor :defType, :sort, :start, :rows, :fq, :fl, # common parameters
:q, :q_dot_alt, :qf, :mm, :pf, :ps, :qs, :tie, :bq, :bf, # Dismax parameters
:sow, :mm_dot_autorelax, :boost, :lowercaseOperators, :pf2, :ps2, :pf3, :ps3, :stopwords, :uf, # Edismax parameters
:facet, :facet_dot_field, :facet_dot_threads,
:hl,
:mlt
attr_accessor :defType, :sort, :start, :rows, :fq, :fl, # common parameters
:q, :q_dot_alt, :qf, :mm, :pf, :ps, :qs, :tie, :bq, :bf, # Dismax parameters
:sow, :mm_dot_autorelax, :boost, :lowercaseOperators, :pf2, :ps2, :pf3, :ps3, :stopwords, :uf, # Edismax parameters
:facet, :facet_dot_field, :facet_dot_threads,
:hl,
:mlt
def initialize(search_type)
@defType = "edismax"
@sort = "score desc"
@start = 0
@rows = 10
# @fq = ["has_model_ssim:(Article OR Issue)"]
@fq = ["has_model_ssim:(Article)"]
@fl = "*,score"
@q = "*:*"
@q_dot_alt = "*:*"
@qf = I18n.t("newspapers.solr_fields").select { |k, v| k.start_with?(search_type == "stemmed" ? "text_stemmed" : "text_exact") }.values # or text_stemmed
@mm = 1
@pf = ""
@ps = ""
@qs = ""
@tie = 0.1
@bq = ""
@bf = ""
@hl = true
@hl_dot_fl = @qf
def initialize search_type
@defType = 'edismax'
@sort = 'score desc'
@start = 0
@rows = 10
# @fq = ["has_model_ssim:(Article OR Issue)"]
@fq = ["has_model_ssim:(Article)"]
@fl = '*,score'
@q = '*:*'
@q_dot_alt = '*:*'
@qf = I18n.t("newspapers.solr_fields").select{|k,v| k.start_with?( search_type=="stemmed" ? "text_stemmed" : "text_exact") }.values # or text_stemmed
@mm = 1
@pf = ""
@ps = ""
@qs = ""
@tie = 0.1
@bq = ""
@bf = ""
@hl = true
@hl_dot_fl = @qf
@json_dot_facet = {}
I18n.t("newspapers.solr_fields").values_at(:language, :newspaper).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true} }
end
I18n.t("newspapers.solr_fields").values_at(:date).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: -1, numBuckets: true} }
end
I18n.t("newspapers.solr_fields").values_at(:month, :day).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true, sort: {index: "asc"}} }
end
I18n.t("newspapers.solr_fields").values_at(:persons, :locations, :organisations, :human_productions).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true} }
end
@json_dot_facet["min_date"] = "min(date_created_dtsi)"
@json_dot_facet["max_date"] = "max(date_created_dtsi)"
@json_dot_facet = {}
I18n.t("newspapers.solr_fields").values_at(:language, :newspaper).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true } }
end
def to_params
p = self.instance_values.select {|k,v| v != "" and !v.nil?}.transform_keys{|k| k.gsub('_dot_','.')}.with_indifferent_access
p["json.facet"] = p["json.facet"].to_json
p
I18n.t("newspapers.solr_fields").values_at(:date).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: -1, numBuckets: true } }
end
I18n.t("newspapers.solr_fields").values_at(:month, :day).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true, sort: { index: "asc" } } }
end
I18n.t("newspapers.solr_fields").values_at(:persons, :locations, :organisations, :human_productions).each do |f|
@json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true } }
end
@json_dot_facet["min_date"] = "min(date_created_dtsi)"
@json_dot_facet["max_date"] = "max(date_created_dtsi)"
end
end
\ No newline at end of file
def to_params
p = self.instance_values.select { |k, v| v != "" and !v.nil? }.transform_keys { |k| k.gsub("_dot_", ".") }.with_indifferent_access
p["json.facet"] = p["json.facet"].to_json
p
end
end
class SolrSearcher
include AbstractSearcher
include AbstractSearcher
@@connection = false
@@connection = false
def self.query params
connect unless @@connection
puts "[SolrSearcher.Query] #{params.to_json}\n" if Rails.env == "development"
@@connection.send_and_receive("select", data: params, method: :post)
end
def self.query(params)
connect unless @@connection
# puts "[SolrSearcher.Query] #{params.to_json}\n" if Rails.env == "development"
@@connection.send_and_receive("select", data: params, method: :post)
end
def self.connect
@@connection = RSolr.connect(url: Rails.configuration.solr['url']) unless @@connection
end
def self.connect
@@connection = RSolr.connect(url: Rails.configuration.solr["url"]) unless @@connection
end
def self.get_doc_by_id(id)
connect unless @@connection
docs = @@connection.send_and_receive("select", data: {q: "id:#{id}"}, method: :post)['response']['docs']
if docs.empty?
nil
else
docs[0]
end
def self.get_doc_by_id(id)
connect unless @@connection
docs = @@connection.send_and_receive("select", data: { q: "id:#{id}" }, method: :post)["response"]["docs"]
if docs.empty?
nil
else
docs[0]
end
end
\ No newline at end of file
end
end
class Tool < ActiveRecord::Base
belongs_to :experiment, optional: false
belongs_to :experiment, optional: false
def to_h
{
def to_h
{
"tool": {
"id": self.id
"id": self.id,
},
"children": []
"children": [],
}
end
def runnable?
self.status == "configured" && (self.parent_id.nil? || Tool.find(self.parent_id).status == "finished")
end
end
def run(continue=false)
"#{self.tool_type}_worker".camelize.constantize.perform_async(self.id, self.experiment.user.id, self.experiment.id, self.tool_type, self.parameters, continue)
end
def runnable?
self.status == "configured" && (self.parent_id.nil? || Tool.find(self.parent_id).status == "finished")
end
def run(continue = false)
"#{self.tool_type}_worker".camelize.constantize.perform_async(self.id, self.experiment.user.id, self.experiment.id, self.tool_type, self.parameters, continue)
end
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
attribute :labs_user_id, presence: true, unique: true
attribute :labs_user_name, presence: true, unique: true
has_many :experiments
has_many :datasets
has_many :notifications
has_many :compound_articles
has_many :experiments
has_many :datasets
has_many :notifications
has_many :compound_articles
has_many :active_sessions
def datasets_with_doc doc_id
self.datasets.map do |dataset|
[dataset.id, dataset.title] if dataset.contains doc_id.to_s
end.delete_if(&:nil?)
end
def compounds_by_issue
out = {}
self.compound_articles.each do |compound_article|
out[compound_article.issue_id] = [] unless out.has_key? compound_article.issue_id
out[compound_article.issue_id] << compound_article
end
out
end
def datasets_with_doc(doc_id)
self.datasets.map do |dataset|
[dataset.id, dataset.title] if dataset.contains doc_id.to_s
end.delete_if(&:nil?)
end
def researcher?
Rails.configuration.auths['emails'].include? self.email
def compounds_by_issue
out = {}
self.compound_articles.each do |compound_article|
out[compound_article.issue_id] = [] unless out.has_key? compound_article.issue_id
out[compound_article.issue_id] << compound_article
end
out
end
def researcher?
Rails.configuration.auths["emails"].include? self.email
end
end
......@@ -7,9 +7,9 @@
<div class="p-0 card-body d-flex align-items-center justify-content-center flex-column">
<ul class="list-group w-100">
<% compound_articles.each do |compound_article| %>
<li class="list-group-item cmpnd-article" data-compound-id="<%= compound_article.id %>" data-parts="<%= compound_article.parts.to_json %>">
<li class="list-group-item cmpnd-article" data-compound-id="<%= compound_article.id %>" data-parts="<%= compound_article.parts.to_json %>" data-title="<%= compound_article.title %>">
<div class="text_part d-inline"><%= compound_article.title %></div>
<a class="delete_compound_article text-danger float-end" href="#"><span class="fas fa-times"></span></a>
<a class="delete_compound_article text-danger float-end" href="#"><span class="fas fa-trash"></span></a>
</li>
<% end %>
</ul>
......
......@@ -15,7 +15,7 @@
<div class="accordion-body" data-controller="date-facets"
data-date-facets-max-date-value="<%= datepicker_max_date %>"
data-date-facets-min-date-value="<%= datepicker_min_date %>">
<form action="/search" method="get">
<form action="./search" method="get">
<div class="input-group mb-2">
<span class="input-group-text">From</span>
<input class="form-control" type="date" id="date_facet_from" name="f[date_created_dtsi][from]"
......