diff --git a/.gitignore b/.gitignore index b7384f2d..6c8aaade 100755 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ app/config/**/parameters.yml app/config/common/security.yml app/Resources/views/institution/* web/css/institution/* +web/js/institution/* src/AppBundle/Form/Type/ContactFormEmailType.php SolrIndexer.py diff --git a/app/Resources/views/analytics.html.twig b/app/Resources/views/analytics.html.twig index d6635824..9fd49442 100644 --- a/app/Resources/views/analytics.html.twig +++ b/app/Resources/views/analytics.html.twig @@ -1,3 +1 @@ {# Insert your analytics code snippet here #} - diff --git a/app/Resources/views/default/add_dataset_admin.html.twig b/app/Resources/views/default/add_dataset_admin.html.twig index 16aeebaa..fdb5792b 100755 --- a/app/Resources/views/default/add_dataset_admin.html.twig +++ b/app/Resources/views/default/add_dataset_admin.html.twig @@ -148,6 +148,7 @@ col-sm-4 {{ form_row(form.publications) }} {{ form_row(form.awards) }} + {{ form_row(form.projects) }} {% if userIsAdmin %} {# RELATED DATASETS #}
UID: {{ dataset.id }}
diff --git a/app/Resources/views/default/view_dataset_internal.html.twig b/app/Resources/views/default/view_dataset_internal.html.twig index 0c755fb7..7063a52c 100755 --- a/app/Resources/views/default/view_dataset_internal.html.twig +++ b/app/Resources/views/default/view_dataset_internal.html.twig @@ -1,39 +1,8 @@ {% extends 'base.html.twig' %} {% from 'default/_JSONLD_output.html.twig' import JSONLD_output %} -{% block page_scripts %} - +{% block page_scripts %} + {% endblock %} @@ -132,6 +101,11 @@ $(function () { {% endif %} + {% if dataset.getProjects is not empty %} + {% for project in dataset.getProjects %} +UID: {{ dataset.id }}
diff --git a/app/config/common/config.yml b/app/config/common/config.yml index 3a858df8..30a20dbc 100755 --- a/app/config/common/config.yml +++ b/app/config/common/config.yml @@ -23,6 +23,7 @@ framework: # handler_id set to null will use default session handler from php.ini handler_id: session.handler.native_file save_path: "%kernel.root_dir%/sessions" + cookie_secure: true fragments: ~ http_method_override: true diff --git a/app/config/common/services.yml b/app/config/common/services.yml index b80aba42..8a4da18b 100755 --- a/app/config/common/services.yml +++ b/app/config/common/services.yml @@ -32,3 +32,7 @@ services: # service_name: # class: AppBundle\Directory\ClassName # arguments: ["@another_service_name", "plain_value", "%parameter_name%"] + app.security_headers_listener: + class: AppBundle\EventListener\ResponseListener + tags: + - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse } diff --git a/src/AppBundle/Entity/Dataset.php b/src/AppBundle/Entity/Dataset.php index edd4d5ef..5b6fa20e 100755 --- a/src/AppBundle/Entity/Dataset.php +++ b/src/AppBundle/Entity/Dataset.php @@ -209,6 +209,16 @@ class Dataset implements JsonSerializable { protected $awards; + /** + * @ORM\ManyToMany(targetEntity="Project", cascade={"persist"}, inversedBy="datasets") + * @ORM\JoinTable(name="datasets_projects", + * joinColumns={@ORM\JoinColumn(name="dataset_uid",referencedColumnName="dataset_uid")}, + * inverseJoinColumns={@ORM\JoinColumn(name="project_id",referencedColumnName="project_id")} + * ) + */ + protected $projects; + + /** * @ORM\ManyToMany(targetEntity="AccessRestriction", cascade={"persist"}, inversedBy="datasets") * @ORM\JoinTable(name="datasets_access_restrictions", @@ -460,6 +470,7 @@ public function __construct() $this->date_added = new \DateTime("now"); $this->dataset_formats = new \Doctrine\Common\Collections\ArrayCollection(); $this->awards = new \Doctrine\Common\Collections\ArrayCollection(); + $this->projects = new \Doctrine\Common\Collections\ArrayCollection(); $this->access_restrictions = new \Doctrine\Common\Collections\ArrayCollection(); $this->data_collection_instruments = new \Doctrine\Common\Collections\ArrayCollection(); $this->subject_genders = new \Doctrine\Common\Collections\ArrayCollection(); @@ -1109,6 +1120,40 @@ public function getAwards() return $this->awards; } + + /** + * Add projects + * + * @param \AppBundle\Entity\Project $projects + * @return Dataset + */ + public function addProject(\AppBundle\Entity\Project $projects) + { + $this->projects[] = $projects; + + return $this; + } + + /** + * Remove projects + * + * @param \AppBundle\Entity\Project $projects + */ + public function removeProject(\AppBundle\Entity\Project $projects) + { + $this->projects->removeElement($projects); + } + + /** + * Get projects + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getProjects() + { + return $this->projects; + } + /** * Add access_restrictions * @@ -1731,7 +1776,7 @@ public function getDatasetUid() * @return array */ public function jsonSerialize() { - $formats = $awards = $restrictions = $stds = $genders = $sexes = $ages = []; + $formats = $awards = $projects = $restrictions = $stds = $genders = $sexes = $ages = []; $equipment = $software = $subject_of_study = $others = []; $locs = $rel = $areas = $area_details = $domains = $publications = $keywords = $publishers = []; $authors = $data_type_array = $types_of_study = $corresponding_authors = $experts = []; @@ -1755,6 +1800,7 @@ public function jsonSerialize() { foreach ($this->data_types as $data_type) { $data_type_array[]=$data_type->getDisplayName(); } foreach ($this->data_collection_instruments as $std) { $stds[]=$std->getDisplayName(); } foreach ($this->awards as $award) { $awards[]=$award->getDisplayName(); } + foreach ($this->projects as $project) { $projects[]=$project->getDisplayName(); } foreach ($this->local_experts as $expert) { $experts[]=$expert->getDisplayName(); } foreach ($this->subject_domains as $domain) { $domains[]=$domain->getDisplayName(); } foreach ($this->subject_genders as $gender) { $genders[]=$gender->getDisplayName(); } @@ -1793,6 +1839,7 @@ public function jsonSerialize() { 'data_types' => $data_type_array, 'data_collection_standards' => $stds, 'awards' => $awards, + 'projects' => $projects, 'local_experts' => $experts, 'subject_domains' => $domains, 'subject_genders' => $genders, @@ -1813,13 +1860,14 @@ public function jsonSerialize() { */ public function serializeForSolr() { - $formats = $awards = $restrictions = $stds = $genders = $sexes = $ages = $equipment = $software = $subject_of_study = []; + $formats = $projects = $awards = $restrictions = $stds = $genders = $sexes = $ages = $equipment = $software = $subject_of_study = []; $areas = $area_details = $domains = $publications = $keywords = $publishers = []; $authors = $data_type_array = $types_of_study = $corresponding_authors = $experts = $data_locations = $akas = $related_datasets = []; $other_resource_names = $other_resource_descriptions = $related_pubs = $data_location_contents = []; $accession_numbers = $access_instructions = []; foreach ($this->dataset_formats as $format) { $formats[]=$format->getDisplayName(); } foreach ($this->awards as $award) { $awards[]=$award->getDisplayName(); } + foreach ($this->projects as $project) { $projects[]=$project->getDisplayName(); } foreach ($this->access_restrictions as $restriction) { $restrictions[]=$restriction->getDisplayName(); } foreach ($this->data_collection_instruments as $std) { $stds[]=$std->getDisplayName(); } foreach ($this->subject_genders as $gender) { $genders[]=$gender->getDisplayName(); } @@ -1868,6 +1916,7 @@ public function serializeForSolr() { 'study_types' => $types_of_study, 'collection_standards' => $stds, 'awards' => $awards, + 'projects' => $projects, 'access_restrictions' => $restrictions, 'subject_population_ages'=>$ages, 'subject_geographic_area'=>$areas, @@ -1897,7 +1946,7 @@ public function serializeForSolr() { * @return array */ public function serializeComplete() { - $formats = $awards = $restrictions = $stds = $genders = $sexes = $ages = []; + $formats = $projects = $awards = $restrictions = $stds = $genders = $sexes = $ages = []; $equipment = $software = $subject_of_study = $others = []; $locs = $rel = $areas = $area_details = $domains = $publications = $keywords = $publishers = []; $authors = $data_type_array = $types_of_study = $corresponding_authors = $experts = []; @@ -1918,6 +1967,7 @@ public function serializeComplete() { foreach ($this->data_types as $data_type) { $data_type_array[]=$data_type->getDisplayName(); } foreach ($this->data_collection_instruments as $std) { $stds[]=$std->getAllProperties(); } foreach ($this->awards as $award) { $awards[]=$award->getAllProperties(); } + foreach ($this->projects as $project) { $projects[]=$project->getAllProperties(); } foreach ($this->local_experts as $expert) { $experts[]=$expert->getAllProperties(); } foreach ($this->subject_domains as $domain) { $domains[]=$domain->getAllProperties(); } foreach ($this->subject_genders as $gender) { $genders[]=$gender->getDisplayName(); } @@ -1956,6 +2006,7 @@ public function serializeComplete() { 'data_types' => $data_type_array, 'data_collection_standards' => $stds, 'awards' => $awards, + 'projects' => $projects, 'local_experts' => $experts, 'subject_domains' => $domains, 'subject_genders' => $genders, diff --git a/src/AppBundle/Entity/Project.php b/src/AppBundle/Entity/Project.php new file mode 100755 index 00000000..67eb00fe --- /dev/null +++ b/src/AppBundle/Entity/Project.php @@ -0,0 +1,233 @@ +. + * + * @ORM\Entity + * @ORM\Table(name="project") + * @UniqueEntity("project_name") + */ +class Project { + /** + * @ORM\Column(type="integer",name="project_id") + * @ORM\Id + * @ORM\GeneratedValue(strategy="AUTO") + */ + protected $id; + + + /** + * @ORM\Column(type="string",length=255, unique=true) + */ + protected $project_name; + + /** + * @ORM\Column(type="string",length=256) + */ + protected $slug; + + /** + * @ORM\Column(type="string",length=1028, nullable=true) + */ + protected $project_description; + + + /** + * @ORM\Column(type="string",length=1028, nullable=true) + */ + protected $project_url; + + + /** + * @ORM\ManyToMany(targetEntity="Dataset", mappedBy="projects") + **/ + protected $datasets; + + public function __construct() { + $this->datasets = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Get name for display + * + * @return string + */ + public function getDisplayName() { + return $this->project_name; + } + + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set project name + * + * @param string $projectName + * @return Project + */ + public function setProjectName($projectName) + { + $this->project_name = $projectName; + + return $this; + } + + /** + * Get project + * + * @return string + */ + public function getProjectName() + { + return $this->project_name; + } + + /** + * Set project_description + * + * @param string $projectDescription + * @return Project + */ + public function setProjectDescription($projectDescription) + { + $this->project_description = $projectDescription; + + return $this; + } + + /** + * Get project_description + * + * @return string + */ + public function getProjectDescription() + { + return $this->project_description; + } + + /** + * Set project_url + * + * @param string $projectUrl + * @return Project + */ + public function setProjectUrl($projectUrl) + { + $this->project_url = $projectUrl; + + return $this; + } + + /** + * Get project_url + * + * @return string + */ + public function getProjectUrl() + { + return $this->project_url; + } + + /** + * Set slug + * + * @param string $slug + * @return Project + */ + public function setSlug($slug) + { + $this->slug = $slug; + + return $this; + } + + /** + * Get slug + * + * @return string + */ + public function getSlug() + { + return $this->slug; + } + + + /** + * Add datasets + * + * @param \AppBundle\Entity\Dataset $datasets + * @return Project + */ + public function addDataset(\AppBundle\Entity\Dataset $datasets) + { + $this->datasets[] = $datasets; + + return $this; + } + + /** + * Remove datasets + * + * @param \AppBundle\Entity\Dataset $datasets + */ + public function removeDataset(\AppBundle\Entity\Dataset $datasets) + { + $this->datasets->removeElement($datasets); + } + + /** + * Get datasets + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getDatasets() + { + return $this->datasets; + } + + + /** + * Serialize all properties + * + * @return array + */ + public function getAllProperties() + { + return array( + 'project_name' => $this->project_name, + 'project_description' => $this->project_description, + 'project_url' => $this->project_url, + ); + } +} diff --git a/src/AppBundle/EventListener/ResponseListener.php b/src/AppBundle/EventListener/ResponseListener.php new file mode 100644 index 00000000..1ec0321f --- /dev/null +++ b/src/AppBundle/EventListener/ResponseListener.php @@ -0,0 +1,17 @@ +getResponse()->headers->set('Strict-Transport-Security', 'max-age=7776000'); + $event->getResponse()->headers->set('Content-Security-Policy', "default-src 'self' https://netdna.bootstrapcdn.com https://maxcdn.bootstrapcdn.com https://docs.google.com https://www.google-analytics.com https://*.nyu.edu https://*.nyumc.org https://fonts.googleapis.com; script-src 'self' https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com https://www.googletagmanager.com https://www.google-analytics.com https://script.crazyegg.com https://ajax.googleapis.com https://stackpath.bootstrapcdn.com; object-src 'none'; frame-ancestors 'self'; form-action 'self'"); + $event->getResponse()->headers->set('X-Content-Type-Options', 'nosniff'); + } +} + +?> diff --git a/src/AppBundle/Form/Type/DatasetAsAdminType.php b/src/AppBundle/Form/Type/DatasetAsAdminType.php index 1106dbf3..1232fbcf 100755 --- a/src/AppBundle/Form/Type/DatasetAsAdminType.php +++ b/src/AppBundle/Form/Type/DatasetAsAdminType.php @@ -266,6 +266,15 @@ public function buildForm(FormBuilderInterface $builder, array $options) { 'by_reference'=>false, 'label' => 'Grants', )); + $builder->add('projects', 'entity', array( + 'class' => 'AppBundle:Project', + 'property'=> 'project_name', + 'required' => false, + 'attr' => array('id'=>'dataset_projects','style'=>'width:100%'), + 'multiple' => true, + 'by_reference'=>false, + 'label' => 'Related Projects', + )); $builder->add('related_datasets', 'collection', array( 'type' => new DatasetRelationshipType(), 'required' => true, diff --git a/src/AppBundle/Form/Type/ProjectType.php b/src/AppBundle/Form/Type/ProjectType.php new file mode 100755 index 00000000..c455577f --- /dev/null +++ b/src/AppBundle/Form/Type/ProjectType.php @@ -0,0 +1,55 @@ +. + */ +class ProjectType extends AbstractType { + + public function buildForm(FormBuilderInterface $builder, array $options) { + $builder->add('project_name','text',array( + 'label'=>'Project Name', + 'required'=>true, + )); + $builder->add('project_description','text',array( + 'label'=>'Project Description', + 'required'=>false, + )); + $builder->add('project_url','text',array( + 'label'=>'Project URL', + 'required'=>true, + )); + $builder->add('save','submit',array('label'=>'Submit')); + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) { + $resolver->setDefaults(array( + 'data_class' => 'AppBundle\Entity\Project' + )); + } + + public function getName() { + return 'project'; + } + +} + diff --git a/web/css/style.css b/web/css/style.css index bdde06c0..68bab80f 100755 --- a/web/css/style.css +++ b/web/css/style.css @@ -494,6 +494,7 @@ form.remove-form button { .dataset-detail-alttitle, .dataset-detail-id, .dataset-detail-authors, +.dataset-detail-projects, .dataset-detail-issued { color:gray; } diff --git a/web/js/dataset_details.js b/web/js/dataset_details.js new file mode 100644 index 00000000..1b29b467 --- /dev/null +++ b/web/js/dataset_details.js @@ -0,0 +1,58 @@ + +/** +* Record outbound link clicks for Analytics +*/ +var trackOutboundLink = function(url, label) { + gtag('event', 'click', { + 'event_category': 'outbound', + 'event_label': label, + 'transport_type': 'beacon' + }); +} + +/** +* Initialize page popovers +*/ +$(function () { + // initialize Author popovers + $('.dataset-authors-section [data-toggle="popover"]').popover({ + 'html':'true', + 'animation':false, + 'trigger':'manual', + 'placement':'bottom', + }).on("mouseenter", function () { + var _this = this; + $(this).popover("show"); + $(".popover").on("mouseleave", function () { + $(_this).popover('hide'); + }); + }).on("mouseleave", function () { + var _this = this; + setTimeout(function () { + if (!$(".popover:hover").length) { + $(_this).popover("hide"); + } + }, 200); + }); + + // initialize Publisher popovers + $('.publishers-list [data-toggle="popover"]').popover({ + 'html':'true', + 'animation':false, + 'trigger':'manual', + 'placement':'top', + }).on("mouseenter", function () { + var _this = this; + $(this).popover("show"); + $(".popover").on("mouseleave", function () { + $(_this).popover('hide'); + }); + }).on("mouseleave", function () { + var _this = this; + setTimeout(function () { + if (!$(".popover:hover").length) { + $(_this).popover("hide"); + } + }, 200); + }); +}) diff --git a/web/js/searching.js b/web/js/searching.js index b4e09523..f07a8500 100755 --- a/web/js/searching.js +++ b/web/js/searching.js @@ -24,6 +24,7 @@ */ jQuery(function($) { + /** * Interactivity with breadcrumbs */