Skip to content
GitLab
Menu
Why GitLab
Pricing
Contact Sales
Explore
Why GitLab
Pricing
Contact Sales
Explore
Sign in
Get free trial
Commits on Source (2)
creating and accepting subscriptions
· 95c897e9
Mark Harding
authored
Oct 02, 2019
and
Brian Hatchet
committed
Oct 02, 2019
95c897e9
Merge branch 'epic/permissions-sub-reqs' into 'epic/permissions-28'
· cddfe67e
Brian Hatchet
authored
Oct 02, 2019
creating and accepting subscriptions See merge request
!558
cddfe67e
Hide whitespace changes
Inline
Side-by-side
src/app/common/components/post-menu/post-menu.component.spec.ts
View file @
cddfe67e
...
...
@@ -26,6 +26,9 @@ import { FeaturesService } from '../../../services/features.service';
import
{
activityServiceMock
}
from
'
../../../../tests/activity-service-mock.spec
'
;
import
{
storageMock
}
from
'
../../../../tests/storage-mock.spec
'
;
import
{
featuresServiceMock
}
from
'
../../../../tests/features-service-mock.spec
'
;
import
{
Storage
}
from
'
../../../services/storage
'
;
import
{
PermissionsService
}
from
'
../../services/permissions.service
'
;
import
{
MockService
}
from
'
../../../utils/mock
'
;
/* tslint:disable */
/* Mock section */
...
...
@@ -99,6 +102,10 @@ describe('PostMenuComponent', () => {
{
provide
:
OverlayModalService
,
useValue
:
overlayModalServiceMock
},
{
provide
:
ActivityService
,
useValue
:
activityServiceMock
},
{
provide
:
FeaturesService
,
useValue
:
featuresServiceMock
},
{
provide
:
PermissionsService
,
useValue
:
MockService
(
PermissionsService
),
},
{
provide
:
Storage
,
useValue
:
storageMock
},
{
provide
:
BlockListService
,
...
...
@@ -114,6 +121,7 @@ describe('PostMenuComponent', () => {
// synchronous beforeEach
beforeEach
(()
=>
{
featuresServiceMock
.
mock
(
'
allow-comments-toggle
'
,
true
);
featuresServiceMock
.
mock
(
'
permissions
'
,
false
);
fixture
=
TestBed
.
createComponent
(
PostMenuComponent
);
comp
=
fixture
.
componentInstance
;
...
...
src/app/modules/channels/channel.component.html
View file @
cddfe67e
...
...
@@ -145,6 +145,15 @@
>
Subscriptions ({{ user.subscriptions_count }})
</a>
<a
[routerLink]=
"['/', user.username, 'requests']"
*ngIf=
"user.mode === 2 && user.guid == session.getLoggedInUser().guid"
class=
"mdl-tabs__tab"
[ngClass]=
"{ 'is-active': filter === 'requests' }"
>
Requests
</a>
</div>
</div>
...
...
@@ -174,6 +183,15 @@
>
Subscriptions ({{ user.subscriptions_count }})
</a>
<a
[routerLink]=
"['/', user.username, 'requests']"
*ngIf=
"user.mode === 2 && user.guid == session.getLoggedInUser().guid"
class=
"mdl-tabs__tab"
[ngClass]=
"{ 'is-active': filter === 'requests' }"
>
Requests
</a>
</div>
</div>
...
...
@@ -182,6 +200,10 @@
class=
"mdl-grid"
></m-channel--subscribers>
</section>
<section
class=
"mdl-cell mdl-cell--8-col"
*ngIf=
"filter == 'requests'"
>
<m-subscriptionsRequests__list></m-subscriptionsRequests__list>
</section>
</div>
<m-channel--explicit-overlay
[channel]=
"user"
></m-channel--explicit-overlay>
src/app/modules/channels/channel.component.spec.ts
View file @
cddfe67e
...
...
@@ -39,6 +39,7 @@ import { BlockListService } from '../../common/services/block-list.service';
import
{
ChannelMode
}
from
'
../../interfaces/entities
'
;
import
{
ClientMetaService
}
from
'
../../common/services/client-meta.service
'
;
import
{
clientMetaServiceMock
}
from
'
../../../tests/client-meta-service-mock.spec
'
;
import
{
PermissionsService
}
from
'
../../common/services/permissions.service
'
;
describe
(
'
ChannelComponent
'
,
()
=>
{
let
comp
:
ChannelComponent
;
...
...
@@ -50,6 +51,14 @@ describe('ChannelComponent', () => {
MaterialMock
,
MaterialSwitchMock
,
ChannelComponent
,
MockComponent
({
selector
:
'
minds-avatar
'
,
inputs
:
[
'
object
'
,
'
src
'
,
'
editMode
'
,
'
waitForDoneSignal
'
],
}),
MockComponent
({
selector
:
'
minds-button-subscribe
'
,
inputs
:
[
'
user
'
,
'
request
'
],
}),
MockComponent
({
selector
:
'
m-channel--supporters
'
,
inputs
:
[
'
channel
'
],
...
...
@@ -62,6 +71,10 @@ describe('ChannelComponent', () => {
selector
:
'
m-channel--subscribers
'
,
inputs
:
[
'
channel
'
],
}),
MockComponent
({
selector
:
'
m-subscriptionsRequests__list
'
,
inputs
:
[],
}),
MockComponent
({
selector
:
'
m-channel--carousel
'
,
inputs
:
[
'
banners
'
,
'
editMode
'
],
...
...
@@ -108,6 +121,10 @@ describe('ChannelComponent', () => {
{
provide
:
FeaturesService
,
useValue
:
featuresServiceMock
},
{
provide
:
BlockListService
,
useValue
:
MockService
(
BlockListService
)
},
{
provide
:
ClientMetaService
,
useValue
:
clientMetaServiceMock
},
{
provide
:
PermissionsService
,
useValue
:
MockService
(
PermissionsService
),
},
],
}).
compileComponents
();
// compile template and css
}));
...
...
@@ -122,6 +139,7 @@ describe('ChannelComponent', () => {
featuresServiceMock
.
mock
(
'
es-feeds
'
,
false
);
featuresServiceMock
.
mock
(
'
top-feeds
'
,
false
);
featuresServiceMock
.
mock
(
'
channel-filter-feeds
'
,
false
);
featuresServiceMock
.
mock
(
'
permissions
'
,
false
);
comp
=
fixture
.
componentInstance
;
comp
.
username
=
'
username
'
;
comp
.
user
=
{
...
...
src/app/modules/channels/channels.module.ts
View file @
cddfe67e
...
...
@@ -29,6 +29,8 @@ import { HashtagsModule } from '../hashtags/hashtags.module';
import
{
ChannelSortedComponent
}
from
'
./sorted/sorted.component
'
;
import
{
ChannelSortedModuleComponent
}
from
'
./sorted/module.component
'
;
import
{
ReferralsModule
}
from
'
../wallet/tokens/referrals/referrals.module
'
;
import
{
SubscriptionsRequestsListComponent
}
from
'
./requests/list.component
'
;
import
{
SubscriptionsRequestsRequestComponent
}
from
'
./requests/request.component
'
;
const
routes
:
Routes
=
[
{
path
:
'
channels/:filter
'
,
component
:
ChannelsListComponent
},
...
...
@@ -65,6 +67,8 @@ const routes: Routes = [
ExplicitOverlayComponent
,
ChannelSortedComponent
,
ChannelSortedModuleComponent
,
SubscriptionsRequestsListComponent
,
SubscriptionsRequestsRequestComponent
,
],
exports
:
[
ChannelModulesComponent
,
...
...
src/app/modules/channels/requests/list.component.html
0 → 100644
View file @
cddfe67e
<ul
class=
"m-subscriptionsRequests__list"
>
<li
*ngFor=
"let request of requests"
class=
"m-subscriptionsRequestsList__item"
>
<m-subscriptionsRequests__request
[request]=
"request"
></m-subscriptionsRequests__request>
</li>
</ul>
src/app/modules/channels/requests/list.component.scss
0 → 100644
View file @
cddfe67e
.m-subscriptionsRequests__list
{
// @include m-theme() {
// background-color: themed($m-white);
// }
position
:
relative
;
list-style
:
none
;
padding
:
0
;
margin
:
0
;
}
.m-subscriptionRequest__card
{
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
}
padding
:
$minds-padding
*
2
;
margin-bottom
:
$minds-margin
;
display
:
flex
;
flex-direction
:
row
;
align-items
:
center
;
.m-subscriptionRequestCard__avatar
{
width
:
36px
;
height
:
36px
;
border-radius
:
50%
;
}
.m-subscriptionRequestCard__body
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
margin-left
:
$minds-margin
*
2
;
h4
{
padding
:
0
;
margin
:
0
;
font-weight
:
600
;
font-size
:
16px
;
}
span
{
font-size
:
11px
;
color
:
#888
;
}
.m-btn
{
margin-left
:
$minds-margin
;
}
}
}
src/app/modules/channels/requests/list.component.ts
0 → 100644
View file @
cddfe67e
import
{
Component
}
from
'
@angular/core
'
;
import
{
Client
}
from
'
../../../services/api
'
;
@
Component
({
selector
:
'
m-subscriptionsRequests__list
'
,
templateUrl
:
'
./list.component.html
'
,
})
export
class
SubscriptionsRequestsListComponent
{
minds
=
window
.
Minds
;
requests
:
Array
<
any
>
=
[];
constructor
(
private
client
:
Client
)
{}
ngOnInit
()
{
this
.
load
();
}
async
load
()
{
const
{
requests
}
=
<
any
>
(
await
this
.
client
.
get
(
`api/v2/subscriptions/incoming`
)
);
this
.
requests
=
requests
;
}
}
src/app/modules/channels/requests/request.component.html
0 → 100644
View file @
cddfe67e
<a
class=
"m-subscriptionRequest__card m-border"
>
<div
class=
"m-subscriptionRequestCard__avatar"
[style.background-image]=
"
'url(' + minds.cdn_url + '/icon/' + request.subscriber.guid + ')'
"
></div>
<div
class=
"m-subscriptionRequestCard__body"
>
<div
[title]=
"request.subscriber.briefdescription"
>
<h4>
{{ request.subscriber.username }}
</h4>
<span>
{{ request.subscriber.briefdescription }}
</span>
</div>
<div
class=
"m-layout__spacer"
></div>
<ng-container
*ngIf=
"!request.completed; else completed"
>
<button
class=
"m-btn m-btn--action m-btn--slim"
(click)=
"accept($event)"
>
Accept
</button>
<button
class=
"m-btn m-btn--destructive m-btn--slim"
(click)=
"decline($event)"
>
Decline
</button>
</ng-container>
<ng-template
#completed
>
Saved
</ng-template>
</div>
</a>
src/app/modules/channels/requests/request.component.ts
0 → 100644
View file @
cddfe67e
import
{
Component
,
Input
}
from
'
@angular/core
'
;
import
{
Client
}
from
'
../../../services/api
'
;
@
Component
({
selector
:
'
m-subscriptionsRequests__request
'
,
templateUrl
:
'
./request.component.html
'
,
})
export
class
SubscriptionsRequestsRequestComponent
{
minds
=
window
.
Minds
;
@
Input
()
request
;
constructor
(
private
client
:
Client
)
{}
async
accept
()
{
this
.
request
.
declined
=
false
;
this
.
request
.
completed
=
true
;
<
any
>
(
await
this
.
client
.
put
(
`api/v2/subscriptions/incoming/
${
this
.
request
.
subscriber_guid
}
/accept`
)
);
}
async
decline
()
{
this
.
request
.
declined
=
true
;
this
.
request
.
completed
=
true
;
<
any
>
(
await
this
.
client
.
put
(
`api/v2/subscriptions/incoming/
${
this
.
request
.
subscriber_guid
}
/decline`
)
);
}
}
src/app/modules/channels/sidebar/sidebar.spec.ts
View file @
cddfe67e
...
...
@@ -90,7 +90,7 @@ describe('ChannelSidebar', () => {
}),
MockComponent
({
selector
:
'
minds-button-subscribe
'
,
inputs
:
[
'
user
'
],
inputs
:
[
'
user
'
,
'
request
'
],
}),
MockComponent
({
selector
:
'
m-hashtags-selector
'
,
...
...
src/app/modules/channels/tile/tile.component.spec.ts
View file @
cddfe67e
...
...
@@ -50,7 +50,7 @@ describe('ChannelsTileComponent', () => {
}),
MockComponent
({
selector
:
'
minds-button-subscribe
'
,
inputs
:
[
'
user
'
],
inputs
:
[
'
user
'
,
'
request
'
],
}),
MockComponent
({
selector
:
'
m-safe-toggle
'
,
...
...
src/app/modules/groups/profile/groups-settings-button.spec.ts
View file @
cddfe67e
...
...
@@ -19,6 +19,9 @@ import { MockComponent, MockDirective, MockService } from '../../../utils/mock';
import
{
OverlayModalService
}
from
'
../../../services/ux/overlay-modal
'
;
import
{
overlayModalServiceMock
}
from
'
../../../../tests/overlay-modal-service-mock.spec
'
;
import
{
GroupsService
}
from
'
../groups-service
'
;
import
{
FeaturesService
}
from
'
../../../services/features.service
'
;
import
{
featuresServiceMock
}
from
'
../../../../tests/features-service-mock.spec
'
;
import
{
PermissionsService
}
from
'
../../../common/services/permissions.service
'
;
let
groupConfig
=
{
countMembers
:
Promise
.
resolve
(
1
),
...
...
@@ -63,11 +66,17 @@ describe('GroupsSettingsButton', () => {
{
provide
:
Client
,
useValue
:
clientMock
},
{
provide
:
Session
,
useValue
:
sessionMock
},
{
provide
:
OverlayModalService
,
useValue
:
overlayModalServiceMock
},
{
provide
:
FeaturesService
,
useValue
:
featuresServiceMock
},
{
provide
:
PermissionsService
,
useValue
:
MockService
(
PermissionsService
),
},
],
}).
compileComponents
();
}));
beforeEach
(()
=>
{
featuresServiceMock
.
mock
(
'
permissions
'
,
false
);
jasmine
.
MAX_PRETTY_PRINT_DEPTH
=
2
;
jasmine
.
clock
().
uninstall
();
jasmine
.
clock
().
install
();
...
...
src/app/modules/legacy/components/buttons/subscribe.ts
View file @
cddfe67e
...
...
@@ -9,7 +9,7 @@ import { SignupModalService } from '../../../../modules/modals/signup/service';
template
:
`
<button
class="m-btn m-btn--with-icon m-btn--subscribe"
*ngIf="!_user.subscribed"
*ngIf="!_user.subscribed
&& !_user.pending_subscribe
"
(click)="subscribe($event)"
>
<i class="material-icons">person_add</i>
...
...
@@ -25,6 +25,18 @@ import { SignupModalService } from '../../../../modules/modals/signup/service';
</ng-container>
</span>
</button>
<button
class="m-btn m-btn--with-icon m-btn--subscribe subscribed"
*ngIf="_user.pending_subscribe"
(click)="unSubscribe($event)"
>
<i class="material-icons">close</i>
<span>
<ng-container i18n="@@MINDS__BUTTONS__UNSUBSCRIBE__SUBSCRIBED_LABEL"
>Pending</ng-container
>
</span>
</button>
<button
class="m-btn m-btn--with-icon m-btn--subscribe subscribed"
*ngIf="_user.subscribed"
...
...
@@ -72,6 +84,10 @@ export class SubscribeButton {
return
false
;
}
if
(
this
.
_user
.
mode
===
2
)
{
return
this
.
requestSubscribe
();
}
this
.
_user
.
subscribed
=
true
;
this
.
onSubscribed
.
next
();
...
...
@@ -90,6 +106,17 @@ export class SubscribeButton {
});
}
async
requestSubscribe
()
{
this
.
_user
.
pending_subscribe
=
true
;
try
{
await
this
.
client
.
put
(
`api/v2/subscriptions/outgoing/
${
this
.
_user
.
guid
}
`
);
}
catch
(
err
)
{
this
.
_user
.
pending_subscribe
=
false
;
alert
(
'
There was an error requesting to subscribe
'
);
}
}
unSubscribe
(
e
)
{
e
.
preventDefault
();
e
.
stopPropagation
();
...
...
src/app/modules/notifications/notification.component.html
View file @
cddfe67e
...
...
@@ -42,6 +42,41 @@
</a>
</ng-template>
<!-- subscription_request_declined -->
<ng-template
ngSwitchCase=
"subscription_request_declined"
>
<a
[routerLink]=
"['/', notification.fromObj.username || '']"
>
<p>
<span
class=
"pseudo-link mdl-color-text--blue-grey-400"
>
{{
notification.fromObj.name
}}
</span>
rejected your subscription request.
</p>
</a>
</ng-template>
<!-- subscription_request_accepted -->
<ng-template
ngSwitchCase=
"subscription_request_accepted"
>
<a
[routerLink]=
"['/', notification.fromObj.username || '']"
>
<p>
<span
class=
"pseudo-link mdl-color-text--blue-grey-400"
>
{{
notification.fromObj.name
}}
</span>
accepted your subscription request. You are now subscribed.
</p>
</a>
</ng-template>
<ng-template
ngSwitchCase=
"subscription_request_received"
>
<a
[routerLink]=
"['/', session.getLoggedInUser().username, 'requests']"
>
<p>
<span
class=
"pseudo-link mdl-color-text--blue-grey-400"
>
{{
notification.fromObj.name
}}
</span>
has requested to subscribe to you.
</p>
</a>
</ng-template>
<!-- referral ping -->
<ng-template
ngSwitchCase=
"referral_ping"
>
<a
[routerLink]=
"['/wallet/tokens/contributions']"
>
...
...