Skip to content

Commit

Permalink
Merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
williambelle committed Aug 29, 2023
2 parents 06b49b4 + e3a169c commit 3ebb4da
Show file tree
Hide file tree
Showing 21 changed files with 322 additions and 36 deletions.
1 change: 1 addition & 0 deletions .jest/setEnvVars.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
process.env.SEARCH_API_ENABLE_CSE='True'
process.env.SEARCH_API_ENABLE_LDAP='True'
process.env.SEARCH_API_ENABLE_ADDRESS='True'
process.env.SEARCH_API_ENABLE_UNIT='True'
process.env.SEARCH_API_ENABLE_GRAPHSEARCH='True'

Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# CHANGELOG

### v0.1.0 / 2023-08-29

- Address route
- Handle ldap client errors
- Improve Docker image (speed and permissions)
- Update prettier from 2.8.7 to 3.0.1
- Fix environment variables for Docker Compose
- Fix 'node' engine requirement
- Improve section deploy in documentation (Ansible)

### v0.0.1 / 2023-08-02

- First version, released on an unsuspecting world.
21 changes: 17 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,21 @@ git push origin main --tags

## Deploy

Log into `ghcr.io` and `os-docker-registry.epfl.ch`, then

```bash
./ansible/searchapisible [--prod]
Log into `ghcr.io`, `os-docker-registry.epfl.ch` and OpenShift, then

```text
Usage: ./ansible/searchapisible [options]
Options:
-h, --help Show help message and exit
--list-tags List all available tags
--prod Deploy in production
-t, --tags Run tasks tagged with these values [string]
-v, --verbose Causes Ansible to print more debug messages
--version Show version number
Examples:
./ansible/searchapisible
./ansible/searchapisible --prod
./ansible/searchapisible --prod -t app.restart
```
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ endif
print-env: check-env
@echo "SEARCH_API_ENABLE_CSE=${SEARCH_API_ENABLE_CSE}"
@echo "SEARCH_API_ENABLE_LDAP=${SEARCH_API_ENABLE_LDAP}"
@echo "SEARCH_API_ENABLE_ADDRESS=${SEARCH_API_ENABLE_ADDRESS}"
@echo "SEARCH_API_ENABLE_UNIT=${SEARCH_API_ENABLE_UNIT}"
@echo "SEARCH_API_ENABLE_GRAPHSEARCH=${SEARCH_API_ENABLE_GRAPHSEARCH}"
@echo ""
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@
- [/api/ldap?q=278890][ldap-1]
- [/api/ldap?q=[email protected]&hl=en][ldap-2]

## Address

### Endpoint

`GET /api/address`

### Parameters

| Name | Type | Comments |
| ---- | -------- | -------------- |
| `q` | `String` | Query (sciper) |

### Examples

- [/api/address?q=278890][address-1]

## Unit

### Endpoint
Expand Down Expand Up @@ -112,3 +128,4 @@ See [Contributing](CONTRIBUTING.md).
[graphsearch-1]: http://127.0.0.1:5555/api/graphsearch?q=math
[graphsearch-2]: http://127.0.0.1:5555/api/graphsearch?q=vetterli&doctype=person
[graphsearch-3]: http://127.0.0.1:5555/api/graphsearch?q=lts&doctype=unit
[address-1]: http://127.0.0.1:5555/api/address?q=278890
2 changes: 2 additions & 0 deletions ansible/roles/search-api-k8s/tasks/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
value: '{{ searchapi_secrets.SEARCH_API_ENABLE_CSE |string }}'
- name: SEARCH_API_ENABLE_LDAP
value: '{{ searchapi_secrets.SEARCH_API_ENABLE_LDAP |string }}'
- name: SEARCH_API_ENABLE_ADDRESS
value: '{{ searchapi_secrets.SEARCH_API_ENABLE_ADDRESS |string }}'
- name: SEARCH_API_ENABLE_UNIT
value: '{{ searchapi_secrets.SEARCH_API_ENABLE_UNIT |string }}'
- name: SEARCH_API_ENABLE_GRAPHSEARCH
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@ services:
image: search-api
container_name: search-api
environment:
- SEARCH_API_ENABLE_CSE=${SEARCH_API_ENABLE_CSE}
- SEARCH_API_ENABLE_LDAP=${SEARCH_API_ENABLE_LDAP}
- SEARCH_API_ENABLE_ADDRESS=${SEARCH_API_ENABLE_ADDRESS}
- SEARCH_API_ENABLE_UNIT=${SEARCH_API_ENABLE_UNIT}
- SEARCH_API_ENABLE_GRAPHSEARCH=${SEARCH_API_ENABLE_GRAPHSEARCH}
- SEARCH_API_CSE_API_KEY=${SEARCH_API_CSE_API_KEY}
- SEARCH_API_CSE_CX=${SEARCH_API_CSE_CX}
- SEARCH_API_CADIDB_HOST=${SEARCH_API_CADIDB_HOST}
- SEARCH_API_CADIDB_PORT=${SEARCH_API_CADIDB_PORT}
- SEARCH_API_CADIDB_DATABASE=${SEARCH_API_CADIDB_DATABASE}
- SEARCH_API_CADIDB_USER=${SEARCH_API_CADIDB_USER}
- SEARCH_API_CADIDB_PASSWORD=${SEARCH_API_CADIDB_PASSWORD}
- SEARCH_API_LDAP_URL=${SEARCH_API_LDAP_URL}
- SEARCH_API_LDAP_ROOTS_FILTER=${SEARCH_API_LDAP_ROOTS_FILTER}
ports:
- '5555:5555'
11 changes: 6 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ RUN \
ENV TZ="Europe/Zurich" \
NODE_ENV="production"

WORKDIR /app
USER node
WORKDIR /usr/src/app

COPY package*.json ./
COPY src /app
COPY --chown=node:node package*.json ./

RUN \
npm ci --omit=dev && \
npm cache clean --force

COPY --chown=node:node src ./

EXPOSE 5555
USER node

CMD [ "dumb-init", "node", "/app/server.js" ]
CMD [ "dumb-init", "node", "/usr/src/app/server.js" ]
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "search-api",
"private": true,
"version": "0.0.1",
"version": "0.1.0",
"description": "EPFL Search Engine API",
"repository": "epfl-si/search-api",
"author": "William Belle <[email protected]>",
"homepage": "https://github.com/epfl-si/search-api#readme",
"engines": {
"node": "^14.17.0 || >=16.0.0"
"node": "^16.10.0 || >=18.0.0"
},
"scripts": {
"docs": "jsdoc -c jsdoc.json",
Expand All @@ -16,8 +16,8 @@
"prettier": "prettier --check --ignore-unknown '**' '!**/*.js' '!**/ansible-deps-cache'",
"prettier:fix": "prettier --write --ignore-unknown '**' '!**/*.js' '!**/ansible-deps-cache'",
"start": "nodemon src/server.js",
"test": "npm run lint && jest --forceExit --verbose",
"test:coverage": "jest --coverage --forceExit --verbose",
"test": "npm run lint && jest --verbose",
"test:coverage": "jest --coverage --verbose",
"test:watch": "jest --watchAll --verbose"
},
"devDependencies": {
Expand Down
6 changes: 6 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const cseRouter = require('./routes/cse.route');
const peopleRouter = require('./routes/people.route');
const unitRouter = require('./routes/unit.route');
const semanticRouter = require('./routes/semantic.route');
const addressRouter = require('./routes/address.route');

const app = express();

Expand Down Expand Up @@ -39,6 +40,11 @@ if (configApi.enableLdap) {
app.use('/api/ldap', peopleRouter);
}

// Address
if (configApi.enableAddress) {
app.use('/api/address', addressRouter);
}

// Unit
if (configApi.enableUnit) {
app.use('/api/unit', unitRouter);
Expand Down
1 change: 1 addition & 0 deletions src/configs/api.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const helper = require('../utils/helper.util');
const api = {
enableCse: helper.setBool('SEARCH_API_ENABLE_CSE'),
enableLdap: helper.setBool('SEARCH_API_ENABLE_LDAP'),
enableAddress: helper.setBool('SEARCH_API_ENABLE_ADDRESS'),
enableUnit: helper.setBool('SEARCH_API_ENABLE_UNIT'),
enableGraphsearch: helper.setBool('SEARCH_API_ENABLE_GRAPHSEARCH')
};
Expand Down
31 changes: 31 additions & 0 deletions src/controllers/address.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const ldapUtil = require('../utils/ldap.util');
const addressService = require('../services/people.service');
const appCache = require('../services/cache.service');

async function get (req, res) {
const q = req.query.q || '';
if (!/^[0-9]{6}$/.test(q)) {
return res.json({});
}

if (appCache.has(req.originalUrl)) {
return res.send(appCache.get(req.originalUrl));
} else {
try {
const ldapResults = await addressService.getPersonBySciper(q);
const jsonResponse = ldapUtil.ldapAddress2api(ldapResults);
appCache.set(req.originalUrl, jsonResponse);
return res.json(jsonResponse);
} catch (err) {
console.error('[error] ', err.message);
return res.status(400).json({
success: false,
error: 'Oops, something went wrong'
});
}
}
}

module.exports = {
get
};
8 changes: 8 additions & 0 deletions src/routes/address.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const express = require('express');
const router = express.Router();

const addressController = require('../controllers/address.controller');

router.get('/', addressController.get);

module.exports = router;
14 changes: 9 additions & 5 deletions src/services/ldap.service.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
const ldap = require('ldapjs');
const ldapConfig = require('../configs/ldap.config');

// http://ldapjs.org/client.html
const client = ldap.createClient(ldapConfig.client);

function getSciper (entry) {
const uids = entry.attributes.filter(
f => f.type === 'uniqueIdentifier'
Expand All @@ -13,6 +10,12 @@ function getSciper (entry) {

function searchAll (base, options) {
return new Promise((resolve, reject) => {
// http://ldapjs.org/client.html
const client = ldap.createClient(ldapConfig.client);
client.on('error', (err) => {
reject(err);
});

client.search(base, options, (x, res) => {
const personsBySciper = {};

Expand All @@ -25,16 +28,17 @@ function searchAll (base, options) {
});

res.on('timeout', (err) => {
console.error('[error] ' + err.message);
client.destroy();
reject(err);
});

res.on('error', (err) => {
console.error('[error] ' + err.message);
client.destroy();
reject(err);
});

res.on('end', () => {
client.destroy();
resolve(personsBySciper);
});
});
Expand Down
52 changes: 51 additions & 1 deletion src/utils/ldap.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ function newLdapAccredMapper (lang) {
return ldapAccredMapper;
}

function newLdapAddressMapper () {
const ldapAddressMapper = {
roomNumber: ['officeList', (val) => val],
postalAddress: ['fullAddress', (val) => val[0]],
postalCode: ['postalCode', (val) => val[0]],
postOfficeBox: ['postOfficeBox', (val) => val[0]]
};
return ldapAddressMapper;
}

function sortAccreds (obj) {
return obj.sort((a, b) => a.rank - b.rank);
}
Expand Down Expand Up @@ -200,10 +210,50 @@ function ldap2api (ldapResults, q, hl) {
return sortPersons(list, q);
}

/**
* Convert LDAP Address search result into API result.
*
* @example
* const ldapUtil = require('../utils/ldap.util');
* const address = ldapUtil.ldapAddress2api(ldapResults, 'Fett');
*
* @param {object} ldapResults The result from the LDAP Address search.
* @param {string} q The query.
* @returns {object} Return the result for the API.
*/
function ldapAddress2api (ldapResults) {
const ldapAddressMapper = newLdapAddressMapper();
const person = {};

for (const [sciper, entry] of Object.entries(ldapResults)) {
person.sciper = sciper;
const listAccreds = [];
for (let acc = 0; acc < entry.length; acc++) {
const accred = {
officeList: [],
path: dn2path(entry[acc].objectName),
acronym: dn2acronym(entry[acc].objectName)
};
for (let att = 0; att < entry[acc].attributes.length; att++) {
if (entry[acc].attributes[att].type in ldapAddressMapper) {
accred[ldapAddressMapper[entry[acc].attributes[att].type][0]] =
ldapAddressMapper[
entry[acc].attributes[att].type
][1](entry[acc].attributes[att].values);
}
}
listAccreds.push(accred);
}
person.accreds = sortAccreds(listAccreds);
}
return person;
}

module.exports = {
buildLdapQueryForPerson,
dn2acronym,
dn2path,
getProfile,
ldap2api
ldap2api,
ldapAddress2api
};
Loading

0 comments on commit 3ebb4da

Please sign in to comment.