Commit ec9a18ad authored by François Agneray's avatar François Agneray
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request !29
parents 7232eb0b ecc4f6ca
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
stages:
- trigger-child-pipelines
anis-client:
stage: trigger-child-pipelines
trigger:
include: client/.gitlab-ci.yml
strategy: depend
only:
changes:
- client/**/*
refs:
- develop
anis-server:
stage: trigger-child-pipelines
trigger:
include: server/.gitlab-ci.yml
strategy: depend
only:
changes:
- server/**/*
refs:
- develop
anis-services:
stage: trigger-child-pipelines
trigger:
include: services/.gitlab-ci.yml
strategy: depend
only:
changes:
- services/**/*
refs:
- develop
\ No newline at end of file
AstroNomical Information System
AstroNomical Information System - ANIS
website: https://anis.lam.fr
Copyright: CNRS - 2021
Address: Centre de donneeS Astrophysique de Marseille (CeSAM)
Address: Centre de donnéeS Astrophysique de Marseille (CeSAM)
Laboratoire d'Astrophysique de Marseille
Ple de l'Etoile, site de Chteau-Gombert
38, rue Frdric Joliot-Curie
Pôle de l'Etoile, site de Château-Gombert
38, rue Frédéric Joliot-Curie
13388 Marseille cedex 13 France
CNRS U.M.R 7326
Anis Server is governed by the CeCILL license under French law and
ANIS is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
......
......@@ -5,23 +5,25 @@ list:
@echo ""
@echo "Useful targets:"
@echo ""
@echo " rebuild > rebuild all images and start containers for dev only"
@echo " start > start containers"
@echo " restart > restart containers"
@echo " stop > stop and kill running containers"
@echo " status > display stack containers status"
@echo " logs > display containers logs"
@echo " install_client > install client dependencies"
@echo " shell_client > shell into angular client container"
@echo " build_client > generate the angular client dist application (html, css, js)"
@echo " test_client > Starts the angular client unit tests"
@echo " install_server > install server dependencies"
@echo " shell_server > shell into php server container"
@echo " rebuild > Rebuild all images and start containers for dev only"
@echo " start > Start containers"
@echo " restart > Restart containers"
@echo " stop > Stop and kill running containers"
@echo " status > Display stack containers status"
@echo " logs > Display containers logs"
@echo " install_client > Install client dependencies"
@echo " shell_client > Shell into angular client container"
@echo " build_client > Generate the angular client dist application (html, css, js)"
@echo " test_client > Run the angular client unit tests and generate code coverage report"
@echo " test_client-live > Run the angular client unit tests on every file change"
@echo " open-coverage > Open the client code coverage report in a browser (only available for Linux)"
@echo " install_server > Install server dependencies"
@echo " shell_server > Shell into php server container"
@echo " test_server > Starts the server php unit tests"
@echo " phpcs > run php code sniffer test suite"
@echo " shell_services > shell into python services"
@echo " create-db > create a database for dev only (need token_enabled=0)"
@echo " remove-pgdata > remove the anis-next database"
@echo " phpcs > Run php code sniffer test suite"
@echo " shell_services > Shell into python services"
@echo " create-db > Create a database for dev only (need token_enabled=0)"
@echo " remove-pgdata > Remove the anis-next database"
@echo ""
rebuild:
......@@ -54,7 +56,13 @@ build_client:
@docker-compose exec client ng build
test_client:
@docker-compose exec client ng test --no-watch --code-coverage
@docker-compose exec client npx jest --coverage --collectCoverageFrom='src/**/*.ts'
test_client_live:
@docker-compose exec client npx jest --watchAll --coverage
open_coverage_report:
xdg-open client/coverage/anis-client/index.html
install_server:
@docker run --init -it --rm --user $(UID):$(GID) \
......
# AstroNomical Information System - ANIS
## Introduction
AstroNomical Information System is a generic web tool that aims to facilitate
the provision of data (Astrophysics), accessible from a database, for the scientific
community.
This software allows you to control one or more databases related to astronomical
projects and allows access to datasets via a web interface or URLs.
Anis is protected by the CeCILL licence (see LICENCE file at the software root).
## Authors
Here is the list of people involved in the development:
* `François Agneray` : Laboratoire d'Astrophysique de Marseille (CNRS)
* `Chrystel Moreau` : Laboratoire d'Astrophysique de Marseille (CNRS)
* `Tifenn Guillas` : Laboratoire d'Astrophysique de Marseille (CNRS)
## More resources:
* [Website](https://anis.lam.fr)
* [Documentation](https://anis.lam.fr/doc/)
## Installing and starting the application
Anis Server contains a Makefile that helps the developer to install and start the application.
To list all operations availables just type `make` in your terminal at the root of this application.
- To install client dependancies: `make install_client`
- To install server dependancies: `make install_server`
- To build or rebuild all docker images and start containers: `make rebuild`
- To start/stop/restart/status all services: `make start|stop|restart|status`
- To display logs for all services: `make logs`
- To open a shell command into client container: `make shell_client`
- To open a shell command into server container: `make shell_server`
- To execute server tests suite: `make test_server`
- To execute php code sniffer: `make phpcs`
- To create the metamodel database: `make create-db`
- TO remove the metadata database: `make remove-pgdata`
## Web interface
In development mode the web interface can be accessed at the following url : http://localhost:4200
......@@ -4,7 +4,7 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
......
stages:
- install_dependencies
- test
- sonar
- build
- dockerize
- deploy
variables:
VERSION: "3.7.0"
SONARQUBE_URL: https://sonarqube.lam.fr
install_dependencies:
image: node:16-slim
stage: install_dependencies
cache:
key: ${CI_COMMIT_REF_SLUG}_client
paths:
- client/node_modules
policy: pull-push
script:
- cd client
- yarn install
test:
image: node:16-slim
stage: test
cache:
key: ${CI_COMMIT_REF_SLUG}_client
paths:
- node_modules
policy: pull
script:
- cd client
- npx jest --coverage --coverageReporters lcov
artifacts:
paths:
- client/coverage
sonar_scanner:
image: sonarsource/sonar-scanner-cli:latest
stage: sonar
cache:
key: ${CI_COMMIT_REF_SLUG}_client
paths:
- client/node_modules
policy: pull
script:
- cd client
- sonar-scanner
-Dsonar.projectKey=anis-client
-Dsonar.sources=src
-Dsonar.projectVersion=$VERSION
-Dsonar.host.url=$SONARQUBE_URL
-Dsonar.login=$SONAR_TOKEN_CLIENT
-Dsonar.exclusions=**.spec.ts
-Dsonar.typescript.lcov.reportPaths=./coverage/anis-client/lcov.info
build:
image: node:16-slim
stage: build
cache:
key: ${CI_COMMIT_REF_SLUG}_client
paths:
- client/node_modules
policy: pull
script:
- cd client
- yarn global add @angular/cli@latest
- ng build
artifacts:
paths:
- client/dist
dockerize:
image: docker:stable
stage: dockerize
cache: {}
script:
- cd client
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $CI_REGISTRY/anis/anis-next/client:latest || true
- docker build --cache-from $CI_REGISTRY/anis/anis-next/client:latest -t $CI_REGISTRY/anis/anis-next/client:latest .
- docker push $CI_REGISTRY/anis/anis-next/client:latest
deploy:
image: alpine
stage: deploy
variables:
GIT_STRATEGY: none
cache: {}
dependencies: []
script:
- apk add --update curl
- curl -XPOST $DEV_WEBHOOK_CLIENT
only:
refs:
- develop
\ No newline at end of file
#!/bin/bash
if [[ -v ANIS_BASE_HREF ]]; then
sed -i 's@<base href="/">@<base href="'$ANIS_BASE_HREF'">@' /usr/share/nginx/html/index.html
fi
exit 0
FROM nginx
COPY ./90-update-base-href.sh /docker-entrypoint.d/
COPY dist/client /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
......@@ -37,7 +37,10 @@
"scripts": [
"node_modules/@fortawesome/fontawesome-free/js/all.js",
"src/assets/samp.js"
]
],
"allowedCommonJsDependencies": [
"keycloak-js"
]
},
"configurations": {
"production": {
......@@ -89,24 +92,6 @@
"options": {
"browserTarget": "client:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
......
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('./tsconfig');
module.exports = {
preset: 'jest-preset-angular',
testMatch: ['**/+(*.)+(spec).+(ts|js)'],
setupFilesAfterEnv: ['<rootDir>/src/test.ts'],
coverageReporters: ['html'],
coverageDirectory: 'coverage/anis-client',
moduleDirectories: ["node_modules", "./"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
prefix: '<rootDir>/',
}),
};
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/client'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
......@@ -5,8 +5,7 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
"watch": "ng build --watch --configuration development"
},
"private": true,
"dependencies": {
......@@ -26,6 +25,7 @@
"@ngrx/store": "12.1.0",
"@ngrx/store-devtools": "12.1.0",
"bootstrap": "4.6",
"d3": "^5.15.1",
"keycloak-angular": "^8.2.0",
"keycloak-js": "^14.0.0",
"ngx-bootstrap": "^7.0.0-rc.1",
......@@ -39,14 +39,14 @@
"@angular-devkit/build-angular": "~12.0.4",
"@angular/cli": "~12.0.4",
"@angular/compiler-cli": "~12.0.4",
"@types/d3": "^5.7.2",
"@types/jasmine": "~3.6.0",
"@types/jest": "^26.0.24",
"@types/node": "^12.11.1",
"jasmine-core": "~3.7.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"jasmine-marbles": "^0.8.3",
"jest": "^27.0.6",
"jest-preset-angular": "^9.0.5",
"typescript": "~4.2.3"
}
}
/**
* This file is part of Anis Client.
*
* @copyright Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import * as authActions from 'src/app/auth/auth.actions';
import * as authSelector from 'src/app/auth/auth.selector';
import { AppConfigService } from 'src/app/app-config.service';
@Injectable({
providedIn: 'root',
})
export class AdminAuthGuard implements CanActivate {
constructor(
protected readonly router: Router,
private store: Store<{ }>,
private config: AppConfigService
) { }
canActivate(): Observable<boolean> {
return combineLatest([
this.store.pipe(select(authSelector.selectUserRoles)),
this.store.pipe(select(authSelector.selectIsAuthenticated))
]).pipe(
map(([userRoles, isAuthenticated]) => {
// Auth disabled
if (!this.config.authenticationEnabled) {
return true;
}
// Force the user to log in if currently unauthenticated.
if (!isAuthenticated) {
this.store.dispatch(authActions.login());
return false;
}
// If authenticated but not admin go to unauthorized page.
if (!userRoles.includes(this.config.adminRole)) {
this.router.navigateByUrl('/unauthorized');
return false;
}
// Let "Router" allow user entering the page
return true;
})
);
}
}
......@@ -11,73 +11,26 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AdminComponent } from './admin.component';
import { InstanceListComponent } from './containers/instance/instance-list.component';
import { NewInstanceComponent } from './containers/instance/new-instance.component';
import { EditInstanceComponent } from './containers/instance/edit-instance.component';
import { ConfigureInstanceComponent } from './containers/instance/configure-instance.component';
import { GroupListComponent } from './containers/group/group-list.component';
import { NewGroupComponent } from './containers/group/new-group.component';
import { EditGroupComponent } from './containers/group/edit-group.component';
import { NewDatasetComponent } from './containers/dataset/new-dataset.component';
import { EditDatasetComponent } from './containers/dataset/edit-dataset.component';
import { AttributeListComponent } from './containers/attribute/attribute-list.component';
import { SurveyListComponent } from './containers/survey/survey-list.component';
import { NewSurveyComponent } from './containers/survey/new-survey.component';
import { EditSurveyComponent } from './containers/survey/edit-survey.component';
import { DatabaseListComponent } from './containers/database/database-list.component';
import { NewDatabaseComponent } from './containers/database/new-database.component';
import { EditDatabaseComponent } from './containers/database/edit-database.component';
import { SettingsComponent } from './containers/settings/settings.component';
import { AdminAuthGuard } from './admin-auth.guard';
const routes: Routes = [
{
path: 'admin', component: AdminComponent, children: [
{ path: '', redirectTo: 'instance-list', pathMatch: 'full' },
{ path: 'instance-list', component: InstanceListComponent },
{ path: 'new-instance', component: NewInstanceComponent },
{ path: 'edit-instance/:iname', component: EditInstanceComponent },
{ path: 'configure-instance/:iname', component: ConfigureInstanceComponent },
{ path: 'configure-instance/:iname/group', component: GroupListComponent },
{ path: 'configure-instance/:iname/new-group', component: NewGroupComponent },
{ path: 'configure-instance/:iname/edit-group/:id', component: EditGroupComponent },
{ path: 'configure-instance/:iname/new-dataset', component: NewDatasetComponent },
{ path: 'configure-instance/:iname/edit-dataset/:dname', component: EditDatasetComponent },
{ path: 'configure-instance/:iname/configure-dataset/:dname', component: AttributeListComponent },
{ path: 'survey-list', component: SurveyListComponent },
{ path: 'new-survey', component: NewSurveyComponent },
{ path: 'edit-survey/:name', component: EditSurveyComponent },
{ path: 'database-list', component: DatabaseListComponent },
{ path: 'new-database', component: NewDatabaseComponent },
{ path: 'edit-database/:id', component: EditDatabaseComponent },
{ path: 'settings', component: SettingsComponent },
{ path: 'settings/:select', component: SettingsComponent }
path: '', component: AdminComponent, canActivate: [AdminAuthGuard], children: [
{ path: '', redirectTo: 'instance/instance-list', pathMatch: 'full' },
{ path: 'instance', loadChildren: () => import('./instance/instance.module').then(m => m.InstanceModule) },
{ path: 'survey', loadChildren: () => import('./survey/survey.module').then(m => m.SurveyModule) },
{ path: 'database', loadChildren: () => import('./database/database.module').then(m => m.DatabaseModule) },
{ path: 'settings', loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule) }
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AdminRoutingModule { }
export const routedComponents = [
AdminComponent,
InstanceListComponent,
NewInstanceComponent,
EditInstanceComponent,
ConfigureInstanceComponent,
GroupListComponent,
NewGroupComponent,
EditGroupComponent,
NewDatasetComponent,
EditDatasetComponent,
AttributeListComponent,
SurveyListComponent,
NewSurveyComponent,
EditSurveyComponent,
DatabaseListComponent,
NewDatabaseComponent,
EditDatabaseComponent,
SettingsComponent
AdminComponent
];
......@@ -10,13 +10,24 @@
import { NgModule } from '@angular/core';
import { SharedModule } from 'src/app/shared/shared.module';
import { DetailRoutingModule, routedComponents } from './detail-routing.module';