Skip to content

Commit

Permalink
Merge branch 'release-0.9.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
iimog committed Nov 3, 2017
2 parents ea2e130 + 4bf4e9b commit 630fa65
Show file tree
Hide file tree
Showing 24 changed files with 655 additions and 144 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
/node_modules/
/.idea/
.web-server-pid
util/.iucn_token
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ npm test
Anything else should be in the [official documentation](http://fennec.readthedocs.io/en/latest/).

## Changes
### 0.9.0 <2017-11-03>
- Add cron capability to docker (#101)
- Add option to use google analytics
- Breaking changes: docker container has to be pulled, `ga_tracking` has to be added to `parameters.yml` (can be empty)
### 0.8.4 <2017-09-27>
- Add API documentation
- Add cors header to make API accessible (#109)
Expand Down
1 change: 1 addition & 0 deletions app/Resources/views/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<link rel="stylesheet" href="{{ asset('assets/css/fennec-font.css') }}">
{% endblock %}
<link rel="icon" type="image/png" href="{{ asset('favicon.png') }}" />
{% block head %}{% endblock %}
</head>
<body>
<div id="globals" style="display:none" data-dbversion="{{ dbversion }}"></div>
Expand Down
8 changes: 8 additions & 0 deletions app/Resources/views/base.navigation.html.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{% extends 'base.html.twig' %}

{% block head %}
{{ parent() }}
{% include 'googleAnalytics/code.html.twig' %}
{% endblock %}

{% block javascripts %}
{{ parent() }}
{% include 'components/base.navigation.dbversion.html.twig' %}
Expand All @@ -24,6 +29,7 @@
{% endfor %}
</select>


<li class="dropdown">
<a class="dropdown-toggle navbar-custom navbar-icon-custom" data-toggle="dropdown" href="#" style="background-color: transparent;">
<i class="fa fa-question-circle"></i> help <i class="fa fa-caret-down"></i>
Expand Down Expand Up @@ -81,6 +87,7 @@
</ul>
</li>
</ul>
{% include 'googleAnalytics/info.html.twig' %}
</div>
<!-- /.sidebar-collapse -->
</div>
Expand All @@ -100,4 +107,5 @@
{% endblock %}
</div>
</div>
{% include 'googleAnalytics/dialog.html.twig' %}
{% endblock %}
38 changes: 38 additions & 0 deletions app/Resources/views/googleAnalytics/code.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% if ga_tracking is not empty %}
<script type="text/javascript">
var gaProperty = '{{ ga_tracking }}';
// Disable tracking if the opt-out cookie exists.
var disableStr = 'ga-disable-' + gaProperty;
if (document.cookie.indexOf(disableStr + '=true') > -1) {
window[disableStr] = true;
$('document').ready(function () {
$('#google-analytics-info').html('<a href="https://www.google.com/intl/en_en/analytics/">Google Analytics</a> is disabled for you');
});
}
// Opt-out function
function gaOptout() {
document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
window[disableStr] = true;
$('#google-analytics-info').html('<a href="https://www.google.com/intl/en_en/analytics/">Google Analytics</a> is disabled for you');
}
function openGADialog() {
var dia = $('#googleAnalyticsDialog');
console.log(dia);
dia.modal();
}
(function (i, s, o, g, r, a, m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)}, i[r].l = 1 * new Date()
;
a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', '{#$google_analytics_id#}', 'auto', {
anonymizeIp: true
});
ga('send', 'pageview');
</script>
{% endif %}
32 changes: 32 additions & 0 deletions app/Resources/views/googleAnalytics/dialog.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% if ga_tracking is not empty %}
<div class="modal fade" id="googleAnalyticsDialog" tabindex="-1" role="dialog" aria-labelledby="googleAnalyticsDialogLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="googleAnalyticsDialogLabel">Google Analytics and privacy (Datenschutz)</h4>
</div>
<div class="modal-body">
<h4>English</h4>
This website uses Google Analytics, a web analytics service provided by Google, Inc. (“Google”). Google Analytics uses “cookies”, which are text files placed on your computer, to help the website analyze how users use the site. The information generated by the cookie about your use of the website will be transmitted to and stored by Google on servers in the United States .
In case IP-anonymisation is activated on this website, your IP address will be truncated within the area of Member States of the European Union or other parties to the Agreement on the European Economic Area. Only in exceptional cases the whole IP address will be first transfered to a Google server in the USA and truncated there. The IP-anonymisation is active on this website.
Google will use this information on behalf of the operator of this website for the purpose of evaluating your use of the website, compiling reports on website activity for website operators and providing them other services relating to website activity and internet usage.
The IP-address, that your Browser conveys within the scope of Google Analytics, will not be associated with any other data held by Google. You may refuse the use of cookies by selecting the appropriate settings on your browser, however please note that if you do this you may not be able to use the full functionality of this website. You can also opt-out from being tracked by Google Analytics with effect for the future by downloading and installing Google Analytics Opt-out Browser Addon for your current web browser: <a href="http://tools.google.com/dlpage/gaoptout?hl=en" style="color:#2795b6">http://tools.google.com/dlpage/gaoptout?hl=en</a>.
As an alternative to the browser Addon or within browsers on mobile devices, you can <a href="javascript:gaOptout()" style="color:#2795b6">click this link</a> in order to opt-out from being tracked by Google Analytics within this website in the future (the opt-out applies only for the browser in which you set it and within this domain). - See more at: http://rechtsanwalt-schwenke.de/google-analytics-rechtssicher-nutzen-anleitung-fuer-webmaster/#sthash.jLLgpAZg.dpuf. An opt-out cookie will be stored on your device, which means that you'll have to click this link again, if you delete your cookies.

<h4>German</h4>
Diese Website benutzt Google Analytics, einen Webanalysedienst der Google Inc. („Google“). Google Analytics verwendet sog. „Cookies“, Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglichen. Die durch den Cookie erzeugten Informationen über Ihre Benutzung dieser Website werden in der Regel an einen Server von Google in den USA übertragen und dort gespeichert.
Im Falle der Aktivierung der IP-Anonymisierung auf dieser Webseite, wird Ihre IP-Adresse von Google jedoch innerhalb von Mitgliedstaaten der Europäischen Union oder in anderen Vertragsstaaten des Abkommens über den Europäischen Wirtschaftsraum zuvor gekürzt. Nur in Ausnahmefällen wird die volle IP-Adresse an einen Server von Google in den USA übertragen und dort gekürzt. Die IP-Anonymisierung ist auf dieser Website aktiv. Im Auftrag des Betreibers dieser Website wird Google diese Informationen benutzen, um Ihre Nutzung der Website auszuwerten, um Reports über die Websiteaktivitäten zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen gegenüber dem Websitebetreiber zu erbringen.
Die im Rahmen von Google Analytics von Ihrem Browser übermittelte IP-Adresse wird nicht mit anderen Daten von Google zusammengeführt. Sie können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern; wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können. Sie können darüber hinaus die Erfassung der durch das Cookie erzeugten und auf Ihre Nutzung der Website bezogenen Daten (inkl. Ihrer IP-Adresse) an Google sowie die Verarbeitung dieser Daten durch Google verhindern, indem sie das unter dem folgenden Link verfügbare Browser-Plugin herunterladen und installieren: <a href="http://tools.google.com/dlpage/gaoptout?hl=de" style="color:#2795b6">http://tools.google.com/dlpage/gaoptout?hl=de</a>.
Alternativ zum Browser-Add-On oder innerhalb von Browsern auf mobilen Geräten, <a title="Google Analytics Opt-Out-Cookie setzen" href="javascript:gaOptout()" style="color:#2795b6">klicken Sie bitte diesen Link</a>, um die Erfassung durch Google Analytics innerhalb dieser Website zukünftig zu verhindern (das Opt Out funktioniert nur in dem Browser und nur für diese Domain). Dabei wird ein Opt-Out-Cookie auf Ihrem Ger&auml;t abgelegt. L&ouml;schen Sie Ihre Cookies in diesem Browser, m&uuml;ssen Sie diesen Link erneut klicken.

</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
{% endif %}
5 changes: 5 additions & 0 deletions app/Resources/views/googleAnalytics/info.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% if ga_tracking is not empty %}
<div id="google-analytics-info" class="sidebar-panel" style="font-size: 75%">
&nbsp;&nbsp;This page uses<a onclick="openGADialog()" style="padding-left: 5px;">Google Analytics (info/opt-out)</a>
</div>
{% endif %}
1 change: 1 addition & 0 deletions app/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ twig:
globals:
fennec_version: "%application_version%"
dbversions: "%dbal%"
ga_tracking: "%ga_tracking%"

# Swiftmailer Configuration
swiftmailer:
Expand Down
2 changes: 2 additions & 0 deletions app/config/parameters.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ parameters:
mailer_user: ~
mailer_password: ~

ga_tracking: ~

github_client_id: ~
github_client_secret: ~
google_client_id: ~
Expand Down
2 changes: 1 addition & 1 deletion app/config/version.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
parameters:
application_version: 0.8.4
application_version: 0.9.0
25 changes: 13 additions & 12 deletions doc/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -383,18 +383,19 @@ IUCN Redlist
IUCN redlist data can be conveniently downloaded using the `API<http://apiv3.iucnredlist.org/>`_.
Before you can query the API you need to register for a token.
Also if you want to put this data into a public instance you have to make sure to always (automatically) update the data to the latest version in order to comply with the terms of use.
For an initial import follow these steps inside your fennec container (you need `jq<https://stedolan.github.io/jq/>`_)::

VERSION=$(curl -sS "apiv3.iucnredlist.org/api/v3/version" | jq --raw-output '.version')
OUT_FILE=IUCN-${VERSION}.json
# put your api token into a file called .iucn_token
wget https://raw.githubusercontent.com/molbiodiv/fennec-cli/master/bin/download_iucn_api.sh
bash download_iucn_api.sh $VERSION $OUT_FILE
perl -F"\t" -ane 'chomp $F[11];print "$F[7]\t$F[11]\t\t\t\n";' IUCN-${VERSION}.tsv >/tmp/iucn.tsv
/fennec/bin/console app:create-traittype --format categorical_free --description "The IUCN Red List of Threatened Species" --ontology_url "http://www.iucnredlist.org" "IUCN Red List"
/fennec/bin/console app:create-webuser "IUCN" # Note user-id for next commands
/fennec/bin/console app:import-trait-entries --user-id 8 --default-citation "IUCN $(date "+%Y"). IUCN Red List of Threatened Species. Version $VERSION <www.iucnredlist.org>" --traittype "IUCN Red List" --mapping scientific_name --skip-unmapped /tmp/iucn.tsv

For convenience there are some scripts that help with download and update of IUCN data.
You first have to do some initial preparation and then add an entry to crontab (in the fennec container)::

mkdir -p /iucn
cd /iucn
echo "YOUR IUCN API TOKEN" >.iucn_token
crontab -e
# Add the following line (without the # at the beginning of the line)
#17 * * * * cd /iucn;/fennec/util/check_download_update_iucn.sh >>iucn_cron.log 2>>iucn_cron.err

This will download the most current version of the IUCN red list via the api and add it to the fennec database.
On the first run the webuser and traittype are automatically generated.
On subsequent runs if the version of IUCN is unchanged nothing happens and if there is a new version the old traits are expired and the new data is loaded.
You will notice that only about half the entries could be mapped by their scientific name.
One reason for that is that many species on the red list are species with a small population size endemic to a small geographic region.

Expand Down
2 changes: 1 addition & 1 deletion doc/api/api_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ define({ "api": [
],
"sampleRequest": [
{
"url": "http://localhost:3141/api/listing/overview"
"url": "http://fennec.molecular.eco/api/listing/overview"
}
],
"filename": "src/AppBundle/API/Listing/Overview.php",
Expand Down
2 changes: 1 addition & 1 deletion doc/api/api_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
],
"sampleRequest": [
{
"url": "http://localhost:3141/api/listing/overview"
"url": "http://fennec.molecular.eco/api/listing/overview"
}
],
"filename": "src/AppBundle/API/Listing/Overview.php",
Expand Down
2 changes: 1 addition & 1 deletion doc/api/api_project.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ define({
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2017-09-26T17:20:02.131Z",
"time": "2017-09-27T10:44:06.432Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
Expand Down
2 changes: 1 addition & 1 deletion doc/api/api_project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2017-09-26T17:20:02.131Z",
"time": "2017-09-27T10:44:06.432Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
Expand Down
2 changes: 1 addition & 1 deletion docker/fennec/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb http://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get update \
&& apt-get install -yq nodejs git postgresql-client libpq-dev unzip vim libdbd-pg-perl liblog-log4perl-perl yarn\
&& apt-get install -yq nodejs git postgresql-client libpq-dev unzip vim libdbd-pg-perl liblog-log4perl-perl yarn jq cron\
&& rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-install pdo pdo_pgsql zip \
&& a2enmod rewrite \
Expand Down
113 changes: 113 additions & 0 deletions src/AppBundle/Command/ExpireTraitEntriesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

namespace AppBundle\Command;

use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ExpireTraitEntriesCommand extends ContainerAwareCommand
{
/**
* @var EntityManager
*/
private $em;

/**
* @var array<int> TraitType ids
*/
private $traitType;

/**
* @var string
*/
private $connectionName;

protected function configure()
{
$this
// the name of the command (the part after "bin/console")
->setName('app:expire-trait-entries')

// the short description shown while running "php bin/console list"
->setDescription('Expire all trait entries of a given trait-type. Useful if a new version is released.')

// the full command description shown when running the command with
// the "--help" option
->setHelp("This command allows you to expire all entries of a trait type...\n")
->addOption('connection', 'c', InputOption::VALUE_REQUIRED, 'The database version')
->addOption('traittype', 't', InputOption::VALUE_REQUIRED, 'The name of the trait type', null)
;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln([
'Expire Trait Entries',
'====================',
'',
]);
if(!$this->checkOptions($input, $output)){
return;
}
$this->initConnection($input);
// Logger has to be disabled, otherwise memory increases linearly
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
gc_enable();
$traitType = $this->em->getRepository('AppBundle:TraitType')->findOneBy(array('type' => $input->getOption('traittype')));
if($traitType === null){
$output->writeln('<error>Error: Unknown traittype '.$traitType.'</error>');
return;
}
$traitFormat = $traitType->getTraitFormat()->getFormat();
$entries = array();
if($traitFormat === 'numerical'){
$entries = $this->em->getRepository('AppBundle:TraitNumericalEntry')->findBy(array(
'traitType' => $traitType,
));
} elseif ($traitFormat === 'categorical_free'){
$entries = $this->em->getRepository('AppBundle:TraitCategoricalEntry')->findBy(array(
'traitType' => $traitType,
));
}
$expiryCount = 0;
$deletionTime = new \DateTime();
foreach($entries as $entry){
if($entry->getDeletionDate() === null){
$entry->setDeletionDate($deletionTime);
$expiryCount++;
}
}
$this->em->flush();
$output->writeln('All entries for trait type "'.$traitType.'" have been expired (Total: '.$expiryCount.')');
}

/**
* @param InputInterface $input
* @param OutputInterface $output
* @return boolean
*/
protected function checkOptions(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('traittype') === null) {
$output->writeln('<error>No trait type given. Use --traittype</error>');
return false;
}
return true;
}

/**
* @param InputInterface $input
*/
protected function initConnection(InputInterface $input)
{
$this->connectionName = $input->getOption('connection');
if ($this->connectionName === null) {
$this->connectionName = $this->getContainer()->get('doctrine')->getDefaultConnectionName();
}
$orm = $this->getContainer()->get('app.orm');
$this->em = $orm->getManagerForVersion($this->connectionName);
}
}
Loading

0 comments on commit 630fa65

Please sign in to comment.