Commit 9c9213ff authored by Manish Kumar's avatar Manish Kumar
Browse files

Discourse service all requests working with proxy except login, logout and get...

Discourse service all requests working with proxy except login, logout and get private messages + small fix to highlight bar in navigation
parent 9e73a5c9
Pipeline #17404 passed with stage
in 2 minutes and 25 seconds
......@@ -79,7 +79,8 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "versusvirus2020:build"
"browserTarget": "versusvirus2020:build",
"proxyConfig": "src/proxy.conf.json"
},
"configurations": {
"production": {
......
export enum DiscourseCategory {
NO_CATEGORY = 1,
RETOURS_SITE = 2,
RESPONSABLES = 3, // admin
SALON = 4 // membres avec confiance > 3
}
\ No newline at end of file
<div class="horizontal-nav col" id="sidebar">
<nav id="nav">
<span id="logo" #img [routerLink]="['/']" (click)="toggleState(1)" skipLocationChange>
<span id="logo" #img [routerLink]="['/']" skipLocationChange>
<img src="../../assets/favicon.svg" height=96>
</span>
<div class="nav__item" #GS><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/']" [routerLinkActiveOptions]="{exact:
true}" class="nav__link" (click)="toggleState(1)"
true}" class="nav__link"
skipLocationChange>{{'NAV.GETTINGSTARTED' | translate}}</a></div>
<div class="nav__item" #maps><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/maps']" class="nav__link" (click)="toggleState(2)"
<div class="nav__item" #maps><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/maps']" class="nav__link"
skipLocationChange>{{'NAV.MAPS' | translate}}</a></div>
<div class="nav__item" #community><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/community']" (click)="toggleState(3)"
<div class="nav__item" #community><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/community']"
class="nav__link" skipLocationChange>{{'NAV.COMMUNITY' | translate}}</a></div>
<!-- <li class="nav__item"><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/messages']"
class="nav__link" skipLocationChange>Messages</a></li> -->
......@@ -16,7 +16,7 @@
class="nav__link" skipLocationChange>{{ 'NAV.PREVENTIVEMEASURES' | translate}}</a></li> -->
<!-- <li class="nav__item"><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/community']"
class="nav__link" skipLocationChange>Messages</a></li> -->
<div class="nav__item" #logIn><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/login']" (click)="toggleState(4)"
<div class="nav__item" #logIn><a [routerLinkActive]="['nav__link--selected']" [routerLink]="['/login']"
class="nav__link" skipLocationChange>{{ 'NAV.LOGIN' | translate }}</a></div>
<div class="nav__item " #exit><a class="nav__link exit" (click)="getAway()">{{ 'NAV.GETMEAWAY' | translate }}</a></div>
</nav>
......
import { Component, OnInit, ViewChild, ElementRef, AfterViewChecked } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { LangService } from '../services/lang.service';
import { Router } from '@angular/router';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Location } from "@angular/common";
import { ChangeDetectorRef } from '@angular/core';
import { fromEvent, Observable, Subscription } from "rxjs";
import { debounceTime } from 'rxjs/operators';
import { DiscourseAuthService } from "../services/discourse-auth.service";
/**
* The main navigation bar of the website animated such that a line is always following the selected component
......@@ -59,7 +59,7 @@ export class HorizontalHeaderComponent implements OnInit, AfterViewChecked {
* @deprecated prfer a generic private method
*/
logInWidth: number;
private selectedOption: number;
private selectedOption: string = '/';
/**
* @constructor HorizontalHeaderComponent constuctor which injects necessary services and initializes the
......@@ -68,8 +68,14 @@ export class HorizontalHeaderComponent implements OnInit, AfterViewChecked {
* @param router the standard angular router service which is necessary for navigation
* @param cdRef the angular change detection service
*/
constructor(public lang: LangService, private router: Router, private cdRef: ChangeDetectorRef, private discourseAuth: DiscourseAuthService) {
constructor(public lang: LangService, private router: Router, private cdRef: ChangeDetectorRef, private location: Location) {
this.translate = lang.getTranslateService();
/**
* Detection of route changes to know when to update the highlight line
*/
this.router.events.subscribe(val => {
if (val instanceof NavigationEnd) this.toggleState(router.url);
});
}
ngOnInit(): void {
......@@ -81,8 +87,6 @@ export class HorizontalHeaderComponent implements OnInit, AfterViewChecked {
this.resizeObservable$.pipe(debounceTime(300)).subscribe( evt => {
this.updateValues();
});
console.log(this.discourseAuth.getUsernameAvailable('manish'));
}
ngAfterViewChecked(): void {
......@@ -100,7 +104,7 @@ export class HorizontalHeaderComponent implements OnInit, AfterViewChecked {
this.communityWidth = this.community.nativeElement.offsetWidth;
this.logInWidth = this.logIn.nativeElement.offsetWidth;
if(updateCheck == 0 && this.GSWidth != updateCheck) this.toggleState(1); // highlight by default 'Getting started' when the component is initialized
if(updateCheck == 0 && this.GSWidth != updateCheck) this.toggleState('/'); // highlight by default 'Getting started' when the component is initialized
else this.toggleState(this.selectedOption); // otherwise update the highlight line for the current navigation option selected
this.cdRef.detectChanges();
......@@ -118,27 +122,20 @@ export class HorizontalHeaderComponent implements OnInit, AfterViewChecked {
*
* @param {number} menuOption the navigation option to highlight
*/
toggleState(menuOption: number) {
toggleState(menuOption: string) {
this.selectedOption = menuOption;
switch (menuOption) {
case 1:
if(menuOption == '/'){
this.position = this.GS.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.GSWidth;
break;
case 2:
this.position = this.maps.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.mapsWidth;
break;
case 3:
this.position = this.community.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.communityWidth;
break;
case 4:
this.position = this.logIn.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.logInWidth;
break;
default:
break;
} else if(menuOption.startsWith('/maps')){
this.position = this.maps.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.mapsWidth;
} else if(menuOption.startsWith('/community')){
this.position = this.community.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.communityWidth;
} else if(menuOption.startsWith('/login')){
this.position = this.logIn.nativeElement.getBoundingClientRect().left + 'px';
this.width = this.logInWidth;
}
}
}
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { HttpClient, HttpResponse, HttpHeaders } from '@angular/common/http';
import { DiscourseAuthUser } from '../interfaces/discourse-auth-user';
import { DiscourseError } from '../interfaces/discourse-error';
import { environment } from '../../environments/environment';
import { environment, APIHeaders } from '../../environments/environment';
import { DiscourseAuthUserSuccess } from '../interfaces/discourse-auth-user-success';
@Injectable({
......@@ -18,41 +18,44 @@ export class DiscourseAuthService {
/**
* Creates an account within the YANA discourse framework.
* @param username - The username of the new user.
* @param password - The password of the new user.
* @param [name=''] - The name of the new user (disregard for anonymous accounts).
* @param [email=''] - The email of the new user (disregard for anonymous accounts, will need a confirmation scheme).
* @param password - The password of the new user (has to be minimum 10 characters).
* @param [name=''] - [Optional] - The name of the new user (disregard for anonymous accounts).
* @param email - The email of the new user, it needs to look "legit" because the system checks that and unique.
*/
async createAccount(username: string, password: string, name: string = '', email: string = ''): Promise<boolean> {
async createAccount(username: string, password: string, name: string = '', email: string): Promise<any> {
const available: boolean = await this.getUsernameAvailable(username);
let succeded = false;
let succeeded: boolean;
let response: DiscourseAuthUserSuccess | DiscourseError;
if (available) {
this.http.post(
'https://discourse.yana.help/users',
await this.http.post(
'/api/users.json',
{
name,
email,
password,
username,
name: name,
email: email,
password: password,
username: username,
active: true,
approved: true,
api_username: environment.apiUsername,
api_key: environment.apiKey,
'user_fields[1]': ''
approved: true // automatically approved for now
},
{
headers: {
'Content-Type': 'application/json'
}
headers: APIHeaders
.set('Content-Type', 'application/json')
}
).subscribe({
next: (value: HttpResponse<DiscourseAuthUserSuccess>) => {
succeded = value.status === 200;
}
});
)
.toPromise()
.then(
(value: DiscourseAuthUserSuccess) => { // Success
succeeded = value.success && value.hasOwnProperty('user_id');
response = value;
},
(err: HttpResponse<DiscourseError>) => { // Error
succeeded = false;
}
);
}
return available && succeded;
return {available: available, succeeded: succeeded, response: response};
}
/**
......@@ -60,15 +63,17 @@ export class DiscourseAuthService {
* @param username - The username to be checked
*/
async getUsernameAvailable(username: string): Promise<boolean> {
let response: DiscourseAuthUserSuccess | DiscourseError;
this.http.get(
`https://discourse.yana.help/${username}.json`
).subscribe({
next: (data: DiscourseAuthUserSuccess | DiscourseError) => {
response = data;
console.log(response);
}
});
let response: DiscourseAuthUserSuccess | DiscourseError; // wrong interface ?
await this.http.get<any>(`/api/users/${username}`, {headers: APIHeaders}).toPromise()
.then(
(data: DiscourseAuthUserSuccess) => { // Success
response = data;
},
(err: DiscourseError) => { // Error
response = err;
}
);
return !response.hasOwnProperty('user');
}
......
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { DiscourseTopic } from '../interfaces/discourse-topic';
import { DiscoursePost } from '../interfaces/discourse-post';
import { DiscourseOrdering } from '../enums/discourse-ordering.enum';
import { DiscourseTopicCollection } from '../interfaces/discourse-topic-collection';
import { DiscoursePostLatest } from '../interfaces/discourse-post-latest';
import { DiscourseOrdering } from '../enums/discourse-ordering.enum';
import { DiscourseCategory } from "../enums/discourse-category.enum";
import { APIHeaders } from "../../environments/environment";
@Injectable({
providedIn: 'root'
......@@ -18,115 +20,249 @@ export class DiscourseContentService {
/**
* Creates a Topic
* @param title - The title of the topic.
* @param raw - TODO: Find out WTF this is for here (required)
* @param [category=0] - The category the topic is a part of.
* @param title - The title of the topic. (needs to be two words at least apparently ?)
* @param raw - body of the topic (20 characters minimum)
* @param category The category the topic is a part of. (1: No category, 2: "Retour vers le site", 3: "Responsables", 4: "Salon")
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information of the topic created. Otherwise, it returns why the call failed.
*/
createTopic(title: string, raw: string, category: number = 0): DiscourseTopic {
let response: DiscourseTopic;
this.http.post<DiscourseTopic>(
'https://discourse.yana.help/posts.json',
async createTopic(title: string, raw: string, category: DiscourseCategory): Promise<any> {
let response: DiscourseTopic | string[];
let succeeded: boolean;
await this.http.post<DiscourseTopic>(
'/api/posts.json',
{
title,
raw,
category
title: title,
raw: raw,
category: category
},
{
headers: {
'Content-Type': 'application/json'
headers: APIHeaders
}
)
.toPromise()
.then(
(data: DiscourseTopic) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
).subscribe({
next: (data: DiscourseTopic) => { response = data; }
});
return response;
);
return {succeeded: succeeded, response: response};
}
/**
* Creates a Post
* Creates a Post (answer to a topic, private discussion)
* @param topicId - The id of the topic this post is within.
* @param raw - The text of the post.
* @param raw - The text of the post. supports html tags formatting (minimum 20 characters)
* @param [replyTo=null] - [Optional] - The number of the post this is a reply to. (number is the order of the post in the topic stream, not id)
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information of the post created. Otherwise, it returns why the call failed.
*/
createPost(topicId: number, raw: string) {
async createPost(topicId: number, raw: string, replyTo: number = null): Promise<any> {
let response: DiscoursePost;
this.http.post<DiscoursePost>(
'https://discourse.yana.help/posts.json',
let succeeded: boolean;
await this.http.post<DiscoursePost>(
'/api/posts.json',
{
topic_id: topicId,
raw
raw: raw,
reply_to_post_number: replyTo
},
{
headers: {
'Content-Type': 'application/json'
}
headers: APIHeaders
}
).subscribe({
next: (data: DiscoursePost) => { response = data; }
});
return response;
)
.toPromise()
.then(
(data: DiscoursePost) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return {succeeded: succeeded, response: response};
}
/**
* Gets a topic using it's id.
* Gets a topic using its id.
* @param topicId - The id of the topic this post is within.
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information of the topic requested. Otherwise, it returns why the call failed.
*/
getTopic(topicId: number): DiscourseTopic {
async getTopic(topicId: number): Promise<any> {
let response: DiscourseTopic;
this.http.get<DiscourseTopic>(
`https://discourse.yana.help/t/${topicId}.json`
).subscribe(
(data: DiscourseTopic) =>
response = data
let succeeded: boolean;
await this.http.get<DiscourseTopic>(
`/api/t/${topicId}.json`
)
.toPromise()
.then(
(data: DiscourseTopic) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return response;
return {succeeded: succeeded, response: response};
}
/**
* Gets a collection of topics that are currently considered at the top (most active / liked)
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information requested. Otherwise, it returns why the call failed.
*/
getTopTopics(): DiscourseTopicCollection {
async getTopTopics(): Promise<any> {
let response: DiscourseTopicCollection;
this.http.get<DiscourseTopicCollection>(
`https://discourse.yana.help/top.json`
).subscribe(
(data: DiscourseTopicCollection) =>
response = data
let succeeded: boolean;
await this.http.get<DiscourseTopicCollection>(
`/api/top.json`
)
.toPromise()
.then(
(data: DiscourseTopicCollection) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return response;
return {succeeded: succeeded, response: response};
}
/**
* Gets a collection of topics given a certain order
* @param order - The order that the topics should be gotten by (ie. "default", "created", "activity", etc.)
* @param [ascending=false] - Whether the order should be reversed.
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information requested. Otherwise, it returns why the call failed.
*/
getLatestTopicsByOrder(order: DiscourseOrdering, ascending: boolean = false): DiscourseTopicCollection {
async getLatestTopicsByOrder(order: DiscourseOrdering, ascending: boolean = false): Promise<any> {
let response: DiscourseTopicCollection;
this.http.get<DiscourseTopicCollection>(
`https://discourse.yana.help/latest.json?order=${order}&ascending=${ascending}`
).subscribe(
(data: DiscourseTopicCollection) =>
response = data
let succeeded: boolean;
await this.http.get<DiscourseTopicCollection>(
`/api/latest.json?order=${order}&ascending=${ascending}`
)
.toPromise()
.then(
(data: DiscourseTopicCollection) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return response;
return {succeeded: succeeded, response: response};
}
/**
* Gets a collection of posts regardless of topics that have been posted.
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information requested. Otherwise, it returns why the call failed.
*/
getLatestPosts(): DiscoursePostLatest {
async getLatestPosts(): Promise<any> {
let response: DiscoursePostLatest;
this.http.get<DiscoursePostLatest>(
`https://discourse.yana.help/posts.json`
).subscribe(
(data: DiscoursePostLatest) =>
response = data
let succeeded: boolean;
await this.http.get<DiscoursePostLatest>(
`/api/posts.json`
)
.toPromise()
.then(
(data: DiscoursePostLatest) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return {succeeded: succeeded, response: response};
}
/**
* Creates a private topic between 2 or more users (equivalent to a start of a private discussion)
* @param title - Title of the private message
* @param target_recipients - The targets of the message (comma separated)
* @param raw - The text of the post. supports html tags formatting (minimum 20 characters)
* @param [replyTo=null] - [Optional] - The number of the post this is a reply to. (number is the order of the post in the topic stream, not id)
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information of the topic created. Otherwise, it returns why the call failed.
*/
async createPrivateDiscussionTopic(title: string, target_recipients: string, raw: string): Promise<any> {
let response: DiscoursePost;
let succeeded: boolean;
await this.http.post<DiscoursePost>(
'/api/posts.json',
{
title: title,
target_recipients: target_recipients,
raw: raw,
archetype: 'private_message',
},
{
headers: APIHeaders
}
)
.toPromise()
.then(
(data: DiscoursePost) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return {succeeded: succeeded, response: response};
}
/**
* Gets list of private messages (!not working, requires login!)
* @param username - The name of the user concerned.
* @return a JSON containing 'succeeded' (if the call succeeded) and 'response' (the response from the server).
* If the call succeeded, the server returns the information of the topic requested. Otherwise, it returns why the call failed.
*/
async getPrivateMessages(username: string): Promise<any> {
let response: any;
let succeeded: boolean;
await this.http.get<any>(
`/api/topics/private-messages/${username}`
)
.toPromise()
.then(
(data: any) => { // Success
response = data;
succeeded = true;
},
(err: HttpErrorResponse) => { // Error
response = err.error.errors;
succeeded = false;
}
);
return response;
return {succeeded: succeeded, response: response};
}
}
export const environment = {
production: true
production: true,
};
import { HttpHeaders } from '@angular/common/http';
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
apiUsername: 'manish',
apiUsername: 'manish', // every call made to the api will be made by this user (post creation, topic creation,...)
apiKey: '7ceefc9a385125dee40cac1eb48181cbbcac63863895a40ff234efe627652b67',
corsPrefix: 'https://cors-anywhere.herokuapp.com/'
};