Commit 5b019ab7 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Add the new wizard compare_publications.

parent 189f9a11
......@@ -7,11 +7,13 @@ import re
from check_tools import check_publication
from gluon.storage import Storage
from harvest_tools import DRY_RUN
from plugin_dbui import Selector
from plugin_dbui import is_foreign_field, get_foreign_field, Selector
DRY_RUN = T(DRY_RUN)
INLINE_ALERT = "<script>Ext.Msg.alert('%s', '%s');</script>"
MSG_NO_AUTHORS = "<br><br>Removing affiliation failed.<br>"\
"Use INSPIRES instead with the tool 'insert MARCXML'"
......@@ -74,6 +76,56 @@ def check_validate():
selector=selector)
def compare_publications():
"""Compare the publication fields for two ids and show only the difference.
The arguments of the URL are id1 and id2.
"""
data = []
if 'id1' not in request.vars or 'id2' not in request.vars:
return INLINE_ALERT % (T('Error'), T('Specify id1 and id2 in the URL'))
row1 = db.publications[request.vars.id1]
row2 = db.publications[request.vars.id2]
# find the fields of row2 which are different from those of row1
# the difference is a set containing (key, value) tuples
s1 = set(row1.items())
s2 = set(row2.items())
for el in s2.difference(s1):
fieldname, value2 = el
if fieldname in ('delete_record', 'update_record'):
continue
# alias
field = db.publications[fieldname]
value1 = row1[fieldname]
# the first data should contains the ids
if fieldname == 'id':
idrow = ['id', value1, value2]
continue
# convert foreign fields
if is_foreign_field(field):
k_tablename, k_fieldname, k_id = get_foreign_field(field)
fieldname = k_fieldname
value1 = db[k_tablename][value1][k_fieldname]
value2 = db[k_tablename][value2][k_fieldname]
data.append([T(fieldname), value1, value2])
# add the ids as the first data
data.insert(0, idrow)
# delegate the rendering to the view
return dict(data=data, title=row1.title)
def extract_authors():
"""Extract a list of authors in a string containing
author name and their affiliation. It also extract authors for a
......
......@@ -91,6 +91,7 @@
'Click on the link %(link)s to verify your email': 'Click on the link %(link)s to verify your email',
'Click on the link http://localhost:8000/track_publications/default/user/reset_password/%(key)s to reset your password': 'Click on the link http://localhost:8000/track_publications/default/user/reset_password/%(key)s to reset your password',
'Client IP': 'Client IP',
'code': 'code',
'Code': 'Code',
'Collaboration': 'Collaboration',
'collaborations': 'collaborations',
......@@ -172,6 +173,7 @@
'Existing': 'Existant',
'export as csv file': 'exporter un fichier CSV',
'extract authors': 'extraire les auteurs',
'Field': 'Champ',
'Fill': 'Remplir',
'Fill all fields': 'Remplir tous les champs',
'Filter': 'Filtrer',
......@@ -217,6 +219,7 @@
'Header/Footer': 'Header/Footer',
'Help': 'Aide',
'Host': 'Host',
'id': 'id',
'Id': 'Id',
'Import/Export': 'Importer/Exporter',
'insert MARCXML': 'insérer MARCXML',
......@@ -365,6 +368,7 @@
'Record ID': 'Record ID',
'Record not link to a conference': 'Enregistrement sans lien à une conférence',
'Records': 'Enregistrements',
'Reference': 'Référence',
'Register': 'Register',
'Registration identifier': 'Registration identifier',
'Registration is pending approval': 'Registration is pending approval',
......
# -*- coding: utf-8 -*-
"""a collection of tools for views.
@author: R. Le Gac
"""
from gluon import current
from gluon.html import B, TABLE, TR
def compare_html(id1, id2):
"""compare two publication identify by their id.
@type id1: int
@param id1: first publication idenfier
@type id2: int
@param id2: second publication idenfier
@rtype: str
@return:
- string containing the table using the HTML syntax
- The table has one row per publication field
- Only difference are shown
"""
db = current.globalenv['db']
row1 = db.publications[id1]
row2 = db.publications[id2]
# sort the field in alphabetic order
keys = row1.keys()
keys.sort()
# Id is always the first one
i = keys.index('id')
if i:
keys.insert(0, keys.pop(i))
# build a table with difference
table, rc = [], 0
for key in keys:
if key in ('delete_record', 'update_record'):
continue
if row1[key] != row2[key]:
# background color is different for even and odd row number
rc += 1
if rc % 2 == 0:
color = '#EFE'
else:
color = '#DFD'
# add a row to the table
table.append(TR(B(key), row1[key], row2[key],
_style="{background-color: %s;}" % color))
return TABLE(*table, _border="1")
def compare_latex(id1, id2):
"""compare two publication identify by their id.
@type id1: int
@param id1: first publication idenfier
@type id2: int
@param id2: second publication idenfier
@rtype: str
@return:
- string containing the table defined by the latex syntax
- The table has one row per publication field
- Only difference are shown
"""
db = current.globalenv['db']
row1 = db.publications[id1]
row2 = db.publications[id2]
# sort the field in alphabetic order
keys = row1.keys()
keys.sort()
# Id is always the first one
i = keys.index('id')
if i:
keys.insert(0, keys.pop(i))
# build a table with difference
table = ["\\begin{longtable}{| l | p{6cm} | p{6cm} |}"]
table.append("\hline")
for key in keys:
if key in ('delete_record', 'update_record'):
continue
if row1[key] != row2[key]:
a = row1[key]
b = row2[key]
if isinstance(a, str) and a.startswith('http'):
a = "\\burl{%s}" % a
if isinstance(b, str) and b.startswith('http'):
b = "\\burl{%s}" % b
table.append(" \\textbf{%s} & %s & %s \\\\ \hline" % (key.replace('_', ' '), a, b))
table.append("\hline")
table.append("\end{longtable}")
return '\n'.join(table)
\ No newline at end of file
......@@ -8,6 +8,7 @@ HEAD
- Check entries with the same value in the origin field.
- Redesign the harvester/check_validate views using inline javascript.
- Redesing the harvester/check_validate views returning LaTex document.
- Add the wizard compare_publications.
0.8.5 (May 2014)
- Migrate to plugin_dbui 0.6.1.1 and web2py 2.9.5
......
......@@ -122,12 +122,16 @@
response.write(P(title, _style="".join(style)))
}}
<!--
The two DIV blocks to hook the Ext JS grid
-->
<div id="grid-{{=divstat}}"></div>
<div id="grid-{{=divlogs}}"></div>
<!--
Inline javascript to instantiate and render the Ext JS grid
-->
<script type="text/javascript">
/**
......@@ -137,9 +141,11 @@
* shows what happen for each publication found in the store.
*/
//
// bind the python and javascript variables
// use the internationalization of web2py to translate grid header
// MANDATORY: escape false to convert properly the quotes
//
{{
def write(value):
return response.write("\n%s" % value, escape=False)
......@@ -161,21 +167,18 @@
}}
/**
* Renderer function returning the string Total
*/
function rTotal() {
return 'Total';
}
/**
* Render the title of the publication as an URL
* Renderer functions
*
* @param {Object} value
* @param {Object} metadata
* @param {Ext.data.Model} record
* @param {Number} rowIndex
* @param {Number} colIndex
* @param {Ext.data.Store} store
* @param {Ext.view.view} view
*
*/
function toURL(value, metadata, record) {
function rTitle(value, metadata, record) {
var pattern = '<a href="{0}" target="_blank">{1}</a>',
rep,
......@@ -191,7 +194,13 @@
return rep;
}
function rTotal() {
return 'Total';
}
//
// instantiate the grids for the STAT
//
var gridStat = Ext.create('Ext.grid.Panel', {
title: trStatistics,
store: Ext.create('Ext.data.ArrayStore', cfgStatStore),
......@@ -218,15 +227,17 @@
renderTo: 'grid-{{=divstat}}'
});
//
// instantiate the grids for the LOGs
// The row are group per database action and sorted by title.
// Each title is rendered as an URL pointing to the publication
// in the harvester repository
//
var gridLog = Ext.create('Ext.grid.Panel', {
store: Ext.create('Ext.data.ArrayStore', cfgLogsStore),
columns: [
{xtype: 'rownumberer'},
{text: trTitle, dataIndex: 'title', flex: 3, renderer: toURL},
{text: trTitle, dataIndex: 'title', flex: 3, renderer: rTitle},
{text: trAction, dataIndex: 'txt', flex: 1, hidden: true},
{text: trCollection, dataIndex: 'collection', flex: 1, hidden: true},
{text: trYear, dataIndex: 'year', flex: 1, hidden: true}
......
......@@ -108,13 +108,17 @@
}}
<!--
The two DIV blocks to hook the Ext JS grid
-->
<div id="grid-{{=divstat}}"></div>
<div id="grid-{{=divlogs}}"></div>
<!--
Inline javascript to instantiate and render the Ext JS Grid
-->
<script type="text/javascript">
/**
......@@ -124,9 +128,11 @@
* shows what happen for each publication found in the store.
*/
//
// bind the python and javascript variables
// use the internationalization of web2py to translate grid header
// MANDATORY: escape false to convert properly the quotes
//
{{
def write(value):
return response.write("\n%s" % value, escape=False)
......@@ -149,13 +155,38 @@
}}
/**
* Renderer function returning the string Total
* Renderer functions
*
* @param {Object} value
* @param {Object} metadata
* @param {Ext.data.Model} record
* @param {Number} rowIndex
* @param {Number} colIndex
* @param {Ext.data.Store} store
* @param {Ext.view.view} view
*
*/
function rDuplicate(value, metadata, record) {
var i,
id1 = record.get("id"),
ids = value.split(","),
pattern = '<a href="/{0}/wizards/compare_publications?id1={1}&id2={2}" target="_blank">{2}</a>',
rep = [];
for (i = 0; i < ids.length; i += 1) {
rep.push(Ext.String.format(pattern, App.name, id1, ids[i]));
}
return rep.join(", ");
}
function rTotal() {
return 'Total';
}
//
// instantiate the grids for the Stat
//
var gridStat = Ext.create('Ext.grid.Panel', {
title: trStatistics,
store: Ext.create('Ext.data.ArrayStore', cfgStatStore),
......@@ -173,8 +204,10 @@
renderTo: 'grid-{{=divstat}}'
});
//
// instantiate the grids for the LOGs
// The row are group per error and sorted by title.
//
var gridLog = Ext.create('Ext.grid.Panel', {
store: Ext.create('Ext.data.ArrayStore', cfgLogsStore),
columns: [
......@@ -182,7 +215,7 @@
{text: trTitle, dataIndex: 'title', flex: 3},
{text: trError, dataIndex: 'txt', flex: 1, hidden: true},
{text: trId, dataIndex: 'id', flex: 0.2},
{text: trDuplicate, dataIndex: 'ids', flex: 0.2, hidden: true},
{text: trDuplicate, dataIndex: 'ids', flex: 0.2, hidden: true, renderer: rDuplicate},
{text: trCategory, dataIndex: 'category', flex: 0.2, hidden: true},
{text: trProject, dataIndex: 'project', flex: 0.5, hidden: true},
{text: trYear, dataIndex: 'year', flex: 0.2, hidden: true}
......
......@@ -20,11 +20,11 @@
# prepare the data
# - build the title
# - count errors per project
# - insert URL to compare duplicate entries
# - sort the projects as well as the logs per error and then per title
#
#--------------------------------------------------------------------------
from datetime import datetime
from view_tools import compare_latex
# projects
projects = counters.keys()
......@@ -60,15 +60,30 @@
cnt.error = cnt.found - cnt.ok - cnt.validated
pass
# insert URL to compare duplicate entries
for msg in logs:
for i in range(len(msg.ids)):
id2 = msg.ids[i]
url = URL('wizards',
'compare_publications',
extension=False,
host=True,
scheme=True,
vars=dict(id1=msg.id, id2=id2))
msg.ids[i] = '\href{%s}{%s}' % (url, id2)
pass
pass
# sort the logs per error (txt)
data = {}
for msg in logs:
msg.txt.sort()
error = ', '.join(msg.txt)
if error not in data:
data[error] = []
for error in msg.txt:
if error not in data:
data[error] = []
pass
data[error].append(msg)
pass
data[error].append(msg)
pass
errors = data.keys()
......@@ -96,7 +111,7 @@
write("\\hline")
# table header
tu = (T("Project"), T("Found"), T("Ok"), T("Validated"), T("Error"))
tu = (T("Project"), T("Records"), T("Status OK"), T("Validated"), T("Invalid"))
write( " %s & %s & %s & %s & %s \\\\" % tu)
write("\\hline")
......
{{
#--------------------------------------------------------------------------
#
# The python controller return:
# - data (list of list) field, value1, value2
# - title (str) the title of the publication
#
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#
# prepare the data
# - configure the Ext.data.Array for the grid
#
#--------------------------------------------------------------------------
import json
#
# configure the Ext.data.Array
#
cfg = dict()
cfg['fields'] = [{'name': 'field', 'type': 'string'},
{'name': 'value1', 'type': 'string'},
{'name': 'value2', 'type': 'string'}]
cfg['data'] = data
cfg_store = json.dumps(cfg)
#
# unique identifier for the DIV block associated to a grid
#
divgrid = abs(hash(cfg_store))
}}
<!DOCTYPE html>
<html>
<head>
<title>{{=title}}</title>
<meta charset="UTF-8">
<!--
Load the Ext JS library
This page can be call within the application
as well as from everywhere
-->
<link rel="stylesheet" type="text/css" href="/{{=request.application}}/static/plugin_extjs/resources/css/ext-all.css"/>
<script type="text/javascript" src="/{{=request.application}}/static/plugin_extjs/ext-all.js"></script>
<!--
Javascript executed when the page is loaded
It renders the grid with comparaison results
-->
<script type="text/javascript">
Ext.onReady(function(){
//
// bind the python and javascript variables
// use the internationalization of web2py to translate grid header
// MANDATORY: escape false to convert properly the quotes
//
{{
def write(value):
return response.write("\n%s" % value, escape=False)
write("var cfgStore = %s," % cfg_store)
write(" trField = '%s'," % T('Field'))
write(" trReference = '%s'," % T('Reference'))
write(" trDuplicate = '%s';" % T('Duplicate'))
}}
//
// instantiate the grid
//
var grid = Ext.create('Ext.grid.Panel', {
title: '{{=title}}',
store: Ext.create('Ext.data.ArrayStore', cfgStore),
columns: [
{xtype: 'rownumberer'},
{text: trField, dataIndex: 'field', flex: 1},
{text: trReference, dataIndex: 'value1', flex: 1.5},
{text: trDuplicate, dataIndex: 'value2', flex: 1.5}
],
forceFit: true,
renderTo: 'grid-{{=divgrid}}',
width: 400
});
//
// Instantiate a resizer
//
Ext.create('Ext.resizer.Resizer', {
handles: 'all',
target: grid
});
});
</script>
</head>
<body>
<div id="grid-{{=divgrid}}" style="padding: 30px 0px 0px 40px"></div>
</body>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment