mirror of
https://github.com/morten-olsen/aula-client.git
synced 2026-02-08 01:06:25 +01:00
init
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/node_modules
|
||||
/*.log
|
||||
/.env
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Aula Client [WIP]
|
||||
|
||||
VERY unofficial NodeJS client for www.aula.dk
|
||||
5
jest.config.js
Normal file
5
jest.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
22
package.json
Normal file
22
package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "aula",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"axios-cookiejar-support": "^1.0.1",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"qs": "^6.10.1",
|
||||
"tough-cookie": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/tough-cookie": "^4.0.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"ts-jest": "^27.0.5",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
||||
95
src/Client.ts
Normal file
95
src/Client.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import axios from 'axios';
|
||||
import cookieSupport from 'axios-cookiejar-support';
|
||||
import cheerio from 'cheerio';
|
||||
import tough from 'tough-cookie';
|
||||
import qs from 'qs';
|
||||
|
||||
cookieSupport(axios);
|
||||
|
||||
class AulaClient {
|
||||
#cookies: tough.CookieJar;
|
||||
#username: string;
|
||||
#password: string;
|
||||
#profiles?: any[] = [];
|
||||
#context?: any;
|
||||
|
||||
constructor(username: string, password: string) {
|
||||
this.#cookies = new tough.CookieJar();
|
||||
this.#username = username;
|
||||
this.#password = password;
|
||||
}
|
||||
|
||||
#createLoginCookie = async () => {
|
||||
const profiles = await this.request({
|
||||
method: 'profiles.getProfilesByLogin'
|
||||
});
|
||||
const context = await this.request({
|
||||
method: 'profiles.getProfileContext',
|
||||
portalrole: 'guardian',
|
||||
});
|
||||
this.#profiles = profiles.data.profiles;
|
||||
this.#context = context.data;
|
||||
}
|
||||
|
||||
get loggedIn() {
|
||||
return !!this.context;
|
||||
}
|
||||
|
||||
get profiles() {
|
||||
return this.#profiles!;
|
||||
}
|
||||
|
||||
get context() {
|
||||
return this.#context!;
|
||||
}
|
||||
|
||||
get childIds() {
|
||||
return this.profiles[0].children.map((c: any) => c.id);
|
||||
}
|
||||
|
||||
login = async () => {
|
||||
let response = await axios.get('https://login.aula.dk/auth/login.php?type=unilogin', {
|
||||
jar: this.#cookies,
|
||||
withCredentials: true,
|
||||
});
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (response.config.url === 'https://www.aula.dk:443/portal/') {
|
||||
await this.#createLoginCookie();
|
||||
return;
|
||||
}
|
||||
const page = cheerio.load(response.data);
|
||||
const [form] = page('form');
|
||||
if (!form) {
|
||||
throw new Error('Form not found');
|
||||
}
|
||||
const { action } = form.attribs;
|
||||
const inputs = page('form input');
|
||||
const postData: {[name: string]: string} = {};
|
||||
for (let input of inputs) {
|
||||
const { name, value } = input.attribs;
|
||||
if (name === 'username') {
|
||||
postData.username = this.#username;
|
||||
} else if (name === 'password') {
|
||||
postData.password = this.#password;
|
||||
} else {
|
||||
postData[name] = value;
|
||||
}
|
||||
}
|
||||
response = await axios.post(action, qs.stringify(postData), {
|
||||
jar: this.#cookies,
|
||||
withCredentials: true,
|
||||
});
|
||||
}
|
||||
throw new Error('Login took to many rounds');
|
||||
}
|
||||
|
||||
public request = async <T = any>(query: any) => {
|
||||
const { data } = await axios.get<Response<T>>(`https://www.aula.dk/api/v11?${qs.stringify(query)}`, {
|
||||
jar: this.#cookies,
|
||||
withCredentials: true,
|
||||
})
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export default AulaClient;
|
||||
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import AulaClient from './Client';
|
||||
|
||||
export {
|
||||
AulaClient,
|
||||
};
|
||||
9
src/types/Image.ts
Normal file
9
src/types/Image.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
interface Image {
|
||||
id: number,
|
||||
key: string;
|
||||
bucket: string;
|
||||
isImageScalingPending: boolean;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default Image;
|
||||
17
src/types/InstitutionProfile.ts
Normal file
17
src/types/InstitutionProfile.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import Image from './Image';
|
||||
|
||||
interface InstitutionProfile {
|
||||
profileId: number,
|
||||
id: number,
|
||||
institutionCode: string;
|
||||
institutionName: string;
|
||||
role: 'child' | string;
|
||||
name: string;
|
||||
profilePicture: Image;
|
||||
mainGroup: null;
|
||||
shortName: string;
|
||||
insitutionRolw: 'daycare' | string;
|
||||
metadata: string;
|
||||
}
|
||||
|
||||
export default InstitutionProfile;
|
||||
15
src/types/Profile.ts
Normal file
15
src/types/Profile.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import InstitutionProfile from './InstitutionProfile';
|
||||
|
||||
interface Profile {
|
||||
institutionProfiles: InstitutionProfile[];
|
||||
children: any[];
|
||||
age18AndOlder: null;
|
||||
overConsentAge: null;
|
||||
contactInfoEditable: null;
|
||||
portalRole: 'guardian' | string;
|
||||
isLatestDataPolicyAccepted: boolean;
|
||||
profileId: number;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export default Profile;
|
||||
10
src/types/Response.ts
Normal file
10
src/types/Response.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
interface Response<T = any> {
|
||||
status: {
|
||||
code: number;
|
||||
message: 'OK' | string;
|
||||
};
|
||||
data: T;
|
||||
version: number;
|
||||
module: string;
|
||||
method: string;
|
||||
}
|
||||
18
tests/login.test.ts
Normal file
18
tests/login.test.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
require('dotenv').config();
|
||||
import { AulaClient } from '../src';
|
||||
|
||||
describe('login', () => {
|
||||
let client: AulaClient;
|
||||
|
||||
beforeEach(() => {
|
||||
client = new AulaClient(process.env.USERNAME!, process.env.PASSWORD!);
|
||||
});
|
||||
|
||||
it('should be able to log in', async () => {
|
||||
await client.login();
|
||||
await client.request({
|
||||
method: 'presence.getDailyOverview',
|
||||
childIds: client.childIds,
|
||||
});
|
||||
});
|
||||
});
|
||||
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2018",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"skipLibCheck": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user