mirror of
https://code.equilibrium.co.ao/ITO/doneit-web.git
synced 2026-04-18 20:47:54 +00:00
save
This commit is contained in:
@@ -33,7 +33,7 @@ export class AuthGuard implements CanActivate {
|
|||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
if(this.p.userPermission(this.p.permissionList.Chat.access) == true) {
|
if(this.p.userPermission(this.p.permissionList.Chat.access) == true) {
|
||||||
this.authService.loginChat();
|
// this.authService.loginChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathname = state.url
|
const pathname = state.url
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<div class="title-content width-100 d-flex justify-space-between align-center">
|
<div class="title-content width-100 d-flex justify-space-between align-center">
|
||||||
<div class= "btn-dismiss font-30 cursor-pointer" (click)="close()">
|
<div class= "btn-dismiss font-30 cursor-pointer" (click)="close()">
|
||||||
<ion-icon style="margin-bottom:-8px" *ngIf="ThemeService.currentTheme == 'doneIt' " class="font-35" src="assets/images/theme/doneIticons-arrow-arrow-left.svg"></ion-icon>
|
<ion-icon style="margin-bottom:-8px" *ngIf="ThemeService.currentTheme == 'doneIt' " class="font-35" src="assets/images/theme/doneIt/icons-arrow-arrow-left.svg"></ion-icon>
|
||||||
<ion-icon style="margin-bottom:-8px" slot="end" *ngIf="ThemeService.currentTheme != 'doneIt' " src="assets/images/icons-arrow-arrow-left.svg" class="iconsarrowarrow-left"></ion-icon>
|
<ion-icon style="margin-bottom:-8px" slot="end" *ngIf="ThemeService.currentTheme != 'doneIt' " src="assets/images/icons-arrow-arrow-left.svg" class="iconsarrowarrow-left"></ion-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle d-flex align-center flex-grow-1">
|
<div class="middle d-flex align-center flex-grow-1">
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class UserSession {
|
|||||||
UserName: string
|
UserName: string
|
||||||
Password: string
|
Password: string
|
||||||
RochetChatUserId: string
|
RochetChatUserId: string
|
||||||
Profile: 'PR' | 'MDGPR' | 'Consultant' ;
|
Profile: 'PR' | 'MDGPR' | 'Consultant' | 'Unknown' ;
|
||||||
LoginPreference: 'None' | 'Password' | 'Pin' | null;
|
LoginPreference: 'None' | 'Password' | 'Pin' | null;
|
||||||
PIN: string
|
PIN: string
|
||||||
Inactivity: boolean
|
Inactivity: boolean
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<ion-progress-bar type="indeterminate" *ngIf="showLoader"></ion-progress-bar>
|
<ion-progress-bar type="indeterminate" *ngIf="showLoader"></ion-progress-bar>
|
||||||
|
|
||||||
<div class="conteiner-box px-20 height-100" ng-swipe-up="swipe($event)">
|
<div class="conteiner-box px-20 height-100" ng-swipe-up="swipe($event)">
|
||||||
<div *ngIf="p.userPermission([permissionList.Agenda.access])" class="schedule height-100">
|
<div *ngIf="p.userPermission([p.permissionList.Agenda.access])" class="schedule height-100">
|
||||||
<div class="schedule-header">
|
<div class="schedule-header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<ion-icon class="icon" slot="end" src="assets/images/icons-default-agenda.svg" ></ion-icon>
|
<ion-icon class="icon" slot="end" src="assets/images/icons-default-agenda.svg" ></ion-icon>
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="p.userPermission([permissionList.Gabinete.access])" class="schedule height-100">
|
<div *ngIf="p.userPermission([p.permissionList.Gabinete.access])" class="schedule height-100">
|
||||||
<div class="schedule-header">
|
<div class="schedule-header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<ion-icon class="icon" slot="end" src="assets/images/icons-correspondencias.svg"></ion-icon>
|
<ion-icon class="icon" slot="end" src="assets/images/icons-correspondencias.svg"></ion-icon>
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { BackgroundService } from 'src/app/services/background.service';
|
|||||||
import { momentG } from 'src/plugin/momentG';
|
import { momentG } from 'src/plugin/momentG';
|
||||||
import { ThemeService } from 'src/app/services/theme.service'
|
import { ThemeService } from 'src/app/services/theme.service'
|
||||||
import { Storage } from '@ionic/storage';
|
import { Storage } from '@ionic/storage';
|
||||||
import { PermissionList } from 'src/app/models/permission/permissionList';
|
|
||||||
import { PermissionService } from 'src/app/services/permission.service';
|
import { PermissionService } from 'src/app/services/permission.service';
|
||||||
import { ViewEventPage } from 'src/app/modals/view-event/view-event.page';
|
import { ViewEventPage } from 'src/app/modals/view-event/view-event.page';
|
||||||
import { ChangeProfileService } from 'src/app/services/change-profile.service';
|
import { ChangeProfileService } from 'src/app/services/change-profile.service';
|
||||||
@@ -65,8 +64,6 @@ export class EventsPage implements OnInit {
|
|||||||
|
|
||||||
loggeduser: LoginUserRespose;
|
loggeduser: LoginUserRespose;
|
||||||
|
|
||||||
permissionList = new PermissionList();
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private eventService: EventsService,
|
private eventService: EventsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export class InactivityPage implements OnInit {
|
|||||||
await this.authService.SetSession(attempt, this.userattempt);
|
await this.authService.SetSession(attempt, this.userattempt);
|
||||||
|
|
||||||
if(this.p.userPermission(this.p.permissionList.Chat.access)){
|
if(this.p.userPermission(this.p.permissionList.Chat.access)){
|
||||||
this.authService.loginChat();
|
// this.authService.loginChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getToken();
|
this.getToken();
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ import { SessionStore } from 'src/app/store/session.service';
|
|||||||
import { ClearStoreService } from 'src/app/services/clear-store.service';
|
import { ClearStoreService } from 'src/app/services/clear-store.service';
|
||||||
import { ChangeProfileService } from 'src/app/services/change-profile.service';
|
import { ChangeProfileService } from 'src/app/services/change-profile.service';
|
||||||
import { ThemeService } from 'src/app/services/theme.service';
|
import { ThemeService } from 'src/app/services/theme.service';
|
||||||
import { StorageService } from 'src/app/services/storage.service';
|
|
||||||
import { PermissionService } from 'src/app/services/permission.service';
|
import { PermissionService } from 'src/app/services/permission.service';
|
||||||
import { PermissionList } from 'src/app/models/permission/permissionList';
|
import { PermissionList } from 'src/app/models/permission/permissionList';
|
||||||
import { MessageModel, DeleteMessageModel } from '../../models/beast-orm';
|
import { MessageModel, DeleteMessageModel } from '../../models/beast-orm';
|
||||||
import { RochetChatConnectorService } from 'src/app/services/chat/rochet-chat-connector.service';
|
import { RochetChatConnectorService } from 'src/app/services/chat/rochet-chat-connector.service';
|
||||||
import { Storage } from '@ionic/storage';
|
|
||||||
import { ChatSystemService } from 'src/app/services/chat/chat-system.service';
|
import { ChatSystemService } from 'src/app/services/chat/chat-system.service';
|
||||||
import { ChatService } from 'src/app/services/chat.service';
|
import { ChatService } from 'src/app/services/chat.service';
|
||||||
|
|
||||||
@@ -37,7 +35,6 @@ export class LoginPage implements OnInit {
|
|||||||
loginPreference: string
|
loginPreference: string
|
||||||
|
|
||||||
sessionStore = SessionStore;
|
sessionStore = SessionStore;
|
||||||
permissionList = new PermissionList();
|
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
passwordIcon = "eye";
|
passwordIcon = "eye";
|
||||||
|
|
||||||
@@ -50,10 +47,8 @@ export class LoginPage implements OnInit {
|
|||||||
private clearStoreService: ClearStoreService,
|
private clearStoreService: ClearStoreService,
|
||||||
private changeProfileService: ChangeProfileService,
|
private changeProfileService: ChangeProfileService,
|
||||||
public ThemeService: ThemeService,
|
public ThemeService: ThemeService,
|
||||||
private storageservice: StorageService,
|
|
||||||
public p: PermissionService,
|
public p: PermissionService,
|
||||||
private RochetChatConnectorService: RochetChatConnectorService,
|
private RochetChatConnectorService: RochetChatConnectorService,
|
||||||
private storage: Storage,
|
|
||||||
public ChatSystemService: ChatSystemService,
|
public ChatSystemService: ChatSystemService,
|
||||||
private ChatService: ChatService
|
private ChatService: ChatService
|
||||||
) {}
|
) {}
|
||||||
@@ -128,7 +123,6 @@ export class LoginPage implements OnInit {
|
|||||||
await this.authService.SetSession(attempt, this.userattempt);
|
await this.authService.SetSession(attempt, this.userattempt);
|
||||||
|
|
||||||
if(attempt.ChatData) {
|
if(attempt.ChatData) {
|
||||||
await this.authService.loginChat(attempt.ChatData.data);
|
|
||||||
|
|
||||||
await this.authService.loginToChatWs();
|
await this.authService.loginToChatWs();
|
||||||
this.ChatService.setheader()
|
this.ChatService.setheader()
|
||||||
@@ -157,7 +151,6 @@ export class LoginPage implements OnInit {
|
|||||||
|
|
||||||
|
|
||||||
if(attempt.ChatData) {
|
if(attempt.ChatData) {
|
||||||
await this.authService.loginChat(attempt.ChatData.data);
|
|
||||||
await this.authService.loginToChatWs();
|
await this.authService.loginToChatWs();
|
||||||
this.ChatService.setheader();
|
this.ChatService.setheader();
|
||||||
this.ChatSystemService.loadChat();
|
this.ChatSystemService.loadChat();
|
||||||
|
|||||||
@@ -34,11 +34,9 @@ export class AuthService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private httpService: HttpService,
|
|
||||||
private storageService:StorageService,
|
private storageService:StorageService,
|
||||||
public alertController: AlertController,
|
public alertController: AlertController,
|
||||||
private aesencrypt: AESEncrypt,
|
private aesencrypt: AESEncrypt,
|
||||||
private cookieService: CookieService,
|
|
||||||
private RochetChatConnectorService: RochetChatConnectorService,
|
private RochetChatConnectorService: RochetChatConnectorService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private NfService:NfService,
|
private NfService:NfService,
|
||||||
@@ -96,6 +94,8 @@ export class AuthService {
|
|||||||
session.Profile = 'MDGPR'
|
session.Profile = 'MDGPR'
|
||||||
} else if(session.RoleID == 99999872) {
|
} else if(session.RoleID == 99999872) {
|
||||||
session.Profile = 'Consultant'
|
session.Profile = 'Consultant'
|
||||||
|
} else {
|
||||||
|
session.Profile = 'Unknown'
|
||||||
}
|
}
|
||||||
session.Password = user.password
|
session.Password = user.password
|
||||||
|
|
||||||
@@ -111,14 +111,6 @@ export class AuthService {
|
|||||||
this.initialsService.getInitials(session.FullName);
|
this.initialsService.getInitials(session.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginChat(responseChat?) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async autoLoginChat(expirationDate:number) {
|
|
||||||
}
|
|
||||||
|
|
||||||
loginToChatWs() {
|
loginToChatWs() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ThemeService } from 'src/app/services/theme.service';
|
import { ThemeService } from 'src/app/services/theme.service';
|
||||||
import { StorageService} from 'src/app/services/storage.service';
|
import { StorageService} from 'src/app/services/storage.service';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -15,7 +17,8 @@ export class BackgroundService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private themeservice: ThemeService,
|
private themeservice: ThemeService,
|
||||||
private storageservice: StorageService
|
private storageservice: StorageService,
|
||||||
|
private http: HttpClient,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
online() {
|
online() {
|
||||||
@@ -54,18 +57,33 @@ export class BackgroundService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offline() {
|
async offline() {
|
||||||
document.body.style.setProperty(`--color`, "#ffb703");
|
|
||||||
document.body.style.setProperty(`--color2`, "#ffb703");
|
let opts = {
|
||||||
document.body.style.setProperty(`--color3`, "#ffb703");
|
headers: {},
|
||||||
document.body.style.setProperty(`--color4`, "#ffb703");
|
}
|
||||||
document.body.style.setProperty(`--color5`, "#ffb703");
|
|
||||||
this.storageservice.store('networkCheckStore','offline');
|
try {
|
||||||
this.callBacks.forEach((e) => {
|
await this.http.post(environment.apiURL + "UserAuthentication/Login", '', opts).toPromise();
|
||||||
if (e.type == 'Offline') {
|
} catch (error) {
|
||||||
e.funx()
|
if(error.status != 400) {
|
||||||
|
|
||||||
|
document.body.style.setProperty(`--color`, "#ffb703");
|
||||||
|
document.body.style.setProperty(`--color2`, "#ffb703");
|
||||||
|
document.body.style.setProperty(`--color3`, "#ffb703");
|
||||||
|
document.body.style.setProperty(`--color4`, "#ffb703");
|
||||||
|
document.body.style.setProperty(`--color5`, "#ffb703");
|
||||||
|
this.storageservice.store('networkCheckStore','offline');
|
||||||
|
this.callBacks.forEach((e) => {
|
||||||
|
if (e.type == 'Offline') {
|
||||||
|
e.funx()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerBackService(type: 'Offline' | 'Online' | 'Notification', funx: Function, object = '') {
|
registerBackService(type: 'Offline' | 'Online' | 'Notification', funx: Function, object = '') {
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ export class ChatService {
|
|||||||
setheader() {
|
setheader() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (this.p.userPermission(this.p.permissionList.Chat.access)) {
|
if (this.p.userPermission(this.p.permissionList.Chat.access) && SessionStore.user.ChatData) {
|
||||||
this.headers = new HttpHeaders();
|
this.headers = new HttpHeaders();
|
||||||
|
|
||||||
if (this.p.userPermission(this.p.permissionList.Chat.access)) {
|
if (this.p.userPermission(this.p.permissionList.Chat.access)) {
|
||||||
@@ -364,7 +364,7 @@ export class ChatService {
|
|||||||
|
|
||||||
async refreshtoken() {
|
async refreshtoken() {
|
||||||
|
|
||||||
if(this.headers) {
|
if(this.headers && SessionStore.user.ChatData) {
|
||||||
this.headers = this.headers.set('Authorization', SessionStore.user.BasicAuthKey);
|
this.headers = this.headers.set('Authorization', SessionStore.user.BasicAuthKey);
|
||||||
let options = {
|
let options = {
|
||||||
headers: this.headers
|
headers: this.headers
|
||||||
|
|||||||
@@ -576,6 +576,8 @@ export class ChatSystemService {
|
|||||||
const firstName = capitalizeTxt(roomName.split('.')[0])
|
const firstName = capitalizeTxt(roomName.split('.')[0])
|
||||||
const lastName = capitalizeTxt(roomName.split('.')[1])
|
const lastName = capitalizeTxt(roomName.split('.')[1])
|
||||||
return firstName + ' ' + lastName
|
return firstName + ' ' + lastName
|
||||||
|
} else if(roomData.name) {
|
||||||
|
return roomData.name
|
||||||
} else {
|
} else {
|
||||||
return 'Sem nome'
|
return 'Sem nome'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ export class HeaderPage implements OnInit {
|
|||||||
notificationLength: 0;
|
notificationLength: 0;
|
||||||
SessionStore = SessionStore
|
SessionStore = SessionStore
|
||||||
check: boolean;
|
check: boolean;
|
||||||
permissionList = new PermissionList();
|
|
||||||
|
|
||||||
production = environment.production
|
production = environment.production
|
||||||
environment = environment
|
environment = environment
|
||||||
canOpenSearch = false
|
canOpenSearch = false
|
||||||
|
showProfileModal = false
|
||||||
|
permissionList = new PermissionList();
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -48,6 +50,7 @@ export class HeaderPage implements OnInit {
|
|||||||
router.events.subscribe((val) => {
|
router.events.subscribe((val) => {
|
||||||
this.showSearch = false;
|
this.showSearch = false;
|
||||||
this.canOpenSearch = true;
|
this.canOpenSearch = true;
|
||||||
|
this.showProfileModal = false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -179,19 +182,21 @@ export class HeaderPage implements OnInit {
|
|||||||
return enterAnimation(baseEl).direction('reverse');
|
return enterAnimation(baseEl).direction('reverse');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!this.showProfileModal) {
|
||||||
|
this.showProfileModal = true
|
||||||
|
const modal = await this.modalController.create({
|
||||||
|
component: ProfilePage,
|
||||||
|
cssClass: 'model profile-modal search-submodal',
|
||||||
|
componentProps: {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await modal.present();
|
||||||
|
|
||||||
const modal = await this.modalController.create({
|
modal.onDidDismiss().then(() => {
|
||||||
component: ProfilePage,
|
this.notificationLengthData()
|
||||||
cssClass: 'model profile-modal search-submodal',
|
this.showProfileModal = false
|
||||||
componentProps: {
|
})
|
||||||
}
|
}
|
||||||
});
|
|
||||||
await modal.present();
|
|
||||||
|
|
||||||
modal.onDidDismiss().then(() => {
|
|
||||||
this.notificationLengthData()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
|
|
||||||
// apiURL: 'https://gabinetedigital.dyndns.info/GabineteDigital.Services/V5/api/',
|
// apiURL: 'https://gabinetedigital.dyndns.info/GabineteDigital.Services/V5/api/',
|
||||||
apiURL: 'https://gdapi-dev.dyndns.info/GabineteDigital.Services/V5/api/',
|
apiURL: 'https://gd-api.oapr.gov.ao/GabineteDigital.Services/V5/api/',
|
||||||
// apiURL: 'http://gpr-dev-01.gabinetedigital.local/GabineteDigital.Services/V5/api/',
|
// apiURL: 'http://gpr-dev-01.gabinetedigital.local/GabineteDigital.Services/V5/api/',
|
||||||
// apiChatUrl: 'http://192.168.0.29:3000/api/v1/',
|
// apiChatUrl: 'http://192.168.0.29:3000/api/v1/',
|
||||||
// apiWsChatUrl: 'wss://192.168.0.29:3000/websocket',
|
// apiWsChatUrl: 'wss://192.168.0.29:3000/websocket',
|
||||||
apiChatUrl: 'https://gdchat-dev.dyndns.info/api/v1/',
|
apiChatUrl: 'https://gd-chat.oapr.gov.ao/api/v1/',
|
||||||
apiWsChatUrl: 'wss://gdchat-dev.dyndns.info/websocket',
|
apiWsChatUrl: 'ws://gd-chat.oapr.gov.ao/websocket',
|
||||||
/* apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
/* apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
||||||
apiWsChatUrl: 'wss://www.tabularium.pt/websocket', */
|
apiWsChatUrl: 'wss://www.tabularium.pt/websocket', */
|
||||||
// apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
// apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
||||||
|
|
||||||
production: true,
|
production: true,
|
||||||
domain: 'gabinetedigital.local',
|
domain: 'gabinetedigital.local',
|
||||||
defaultuser: '',//paulo.pinto paulo.pinto@gabinetedigital.local
|
defaultuser: '',//paulo.pinto paulo.pinto@gabinetedigital.local
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
//apiURL: 'https://gabinetedigital.dyndns.info/GabineteDigital.Services/V5/api/',
|
//apiURL: 'https://gabinetedigital.dyndns.info/GabineteDigital.Services/V5/api/',
|
||||||
apiURL: 'http://gpr-dev-01.gabinetedigital.local/GabineteDigital.Services/V5/api/',
|
apiURL: 'https://gd-api.oapr.gov.ao/GabineteDigital.Services/V5/api/',
|
||||||
//apiURL: 'https://gdapi-dev.dyndns.info/GabineteDigital.Services/V5/api/',
|
//apiURL: 'https://gdapi-dev.dyndns.info/GabineteDigital.Services/V5/api/',
|
||||||
apiChatUrl: 'http://192.168.0.29:3000/api/v1/',
|
apiChatUrl: 'https://gd-chat.oapr.gov.ao/api/v1/',
|
||||||
apiWsChatUrl: 'ws://192.168.0.29:3000/websocket',
|
apiWsChatUrl: 'ws://gd-chat.oapr.gov.ao/websocket',
|
||||||
// apiChatUrl: 'https://gdchat-dev.dyndns.info/api/v1/',
|
// apiChatUrl: 'https://gdchat-dev.dyndns.info/api/v1/',
|
||||||
// apiWsChatUrl: 'wss://gdchat-dev.dyndns.info/websocket',
|
// apiWsChatUrl: 'wss://gdchat-dev.dyndns.info/websocket',
|
||||||
/* apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
/* apiChatUrl: 'https://www.tabularium.pt/api/v1/',
|
||||||
|
|||||||
Reference in New Issue
Block a user