Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
7c3ba4ce
Commit
7c3ba4ce
authored
Apr 06, 2017
by
Sean Hammond
Committed by
GitHub
Apr 06, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #336 from hypothesis/update-moderation-api-use
Update moderation API use
parents
8de91da2
b71a6ffa
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
237 additions
and
247 deletions
+237
-247
annotation-metadata.js
src/sidebar/annotation-metadata.js
+12
-0
annotation-ui.js
src/sidebar/annotation-ui.js
+0
-5
annotation.js
src/sidebar/components/annotation.js
+1
-1
moderation-banner.js
src/sidebar/components/moderation-banner.js
+19
-19
annotation-test.js
src/sidebar/components/test/annotation-test.js
+1
-3
annotation-thread-test.js
src/sidebar/components/test/annotation-thread-test.js
+6
-8
moderation-banner-test.js
src/sidebar/components/test/moderation-banner-test.js
+28
-26
annotations.js
src/sidebar/reducers/annotations.js
+56
-0
index.js
src/sidebar/reducers/index.js
+0
-3
moderation.js
src/sidebar/reducers/moderation.js
+0
-127
annotations-test.js
src/sidebar/reducers/test/annotations-test.js
+39
-0
moderation-test.js
src/sidebar/reducers/test/moderation-test.js
+0
-52
store.js
src/sidebar/store.js
+2
-0
annotation_thread.html
src/sidebar/templates/annotation_thread.html
+1
-2
moderation_banner.html
src/sidebar/templates/moderation_banner.html
+1
-1
annotation-fixtures.js
src/sidebar/test/annotation-fixtures.js
+23
-0
annotation-metadata-test.js
src/sidebar/test/annotation-metadata-test.js
+13
-0
store-test.js
src/sidebar/test/store-test.js
+35
-0
No files found.
src/sidebar/annotation-metadata.js
View file @
7c3ba4ce
...
...
@@ -180,9 +180,21 @@ function location(annotation) {
return
Number
.
POSITIVE_INFINITY
;
}
/**
* Return the number of times the annotation has been flagged
* by other users. If moderation data is unavailable, returns 0.
*/
function
flagCount
(
ann
)
{
if
(
!
ann
.
moderation
)
{
return
0
;
}
return
ann
.
moderation
.
flag_count
;
}
module
.
exports
=
{
documentMetadata
:
documentMetadata
,
domainAndTitle
:
domainAndTitle
,
flagCount
:
flagCount
,
isAnnotation
:
isAnnotation
,
isNew
:
isNew
,
isOrphan
:
isOrphan
,
...
...
src/sidebar/annotation-ui.js
View file @
7c3ba4ce
...
...
@@ -39,7 +39,6 @@ var thunk = require('redux-thunk').default;
var
reducers
=
require
(
'./reducers'
);
var
annotationsReducer
=
require
(
'./reducers/annotations'
);
var
framesReducer
=
require
(
'./reducers/frames'
);
var
moderationReducer
=
require
(
'./reducers/moderation'
);
var
selectionReducer
=
require
(
'./reducers/selection'
);
var
sessionReducer
=
require
(
'./reducers/session'
);
var
viewerReducer
=
require
(
'./reducers/viewer'
);
...
...
@@ -96,7 +95,6 @@ module.exports = function ($rootScope, settings) {
var
actionCreators
=
redux
.
bindActionCreators
(
Object
.
assign
({},
annotationsReducer
.
actions
,
framesReducer
.
actions
,
moderationReducer
.
actions
,
selectionReducer
.
actions
,
sessionReducer
.
actions
,
viewerReducer
.
actions
...
...
@@ -119,9 +117,6 @@ module.exports = function ($rootScope, settings) {
frames
:
framesReducer
.
frames
,
isHiddenByModerator
:
moderationReducer
.
isHiddenByModerator
,
flagCount
:
moderationReducer
.
flagCount
,
isSidebar
:
viewerReducer
.
isSidebar
,
},
store
.
getState
);
...
...
src/sidebar/components/annotation.js
View file @
7c3ba4ce
...
...
@@ -479,7 +479,7 @@ function AnnotationController(
};
vm
.
isHiddenByModerator
=
function
()
{
return
annotationUI
.
isHiddenByModerator
(
vm
.
annotation
.
id
)
;
return
vm
.
annotation
.
hidden
;
};
vm
.
isFlagged
=
function
()
{
...
...
src/sidebar/components/moderation-banner.js
View file @
7c3ba4ce
'use strict'
;
var
annotationMetadata
=
require
(
'../annotation-metadata'
);
// @ngInject
function
ModerationBannerController
(
annotationUI
,
flash
,
store
)
{
var
self
=
this
;
this
.
flagCount
=
function
()
{
return
annotation
UI
.
flagCount
(
this
.
annotationId
);
return
annotation
Metadata
.
flagCount
(
self
.
annotation
);
};
this
.
isHidden
=
function
()
{
return
annotationUI
.
isHiddenByModerator
(
this
.
annotationId
);
return
self
.
annotation
.
hidden
;
};
this
.
isReply
=
function
()
{
return
annotationMetadata
.
isReply
(
self
.
annotation
);
};
/**
* Hide an annotation from non-moderator users.
*/
this
.
hideAnnotation
=
function
()
{
store
.
annotation
.
hide
({
id
:
this
.
annotationI
d
}).
then
(
function
()
{
annotationUI
.
annotationHiddenChanged
(
this
.
annotationId
,
true
);
}).
catch
(
function
(
err
)
{
flash
.
error
(
err
.
message
);
store
.
annotation
.
hide
({
id
:
self
.
annotation
.
i
d
}).
then
(
function
()
{
annotationUI
.
hideAnnotation
(
self
.
annotation
.
id
);
}).
catch
(
function
()
{
flash
.
error
(
'Failed to hide annotation'
);
});
};
...
...
@@ -25,10 +33,10 @@ function ModerationBannerController(annotationUI, flash, store) {
* Un-hide an annotation from non-moderator users.
*/
this
.
unhideAnnotation
=
function
()
{
store
.
annotation
.
unhide
({
id
:
this
.
annotationI
d
}).
then
(
function
()
{
annotationUI
.
annotationHiddenChanged
(
this
.
annotationId
,
false
);
}).
catch
(
function
(
err
)
{
flash
.
error
(
err
.
message
);
store
.
annotation
.
unhide
({
id
:
self
.
annotation
.
i
d
}).
then
(
function
()
{
annotationUI
.
unhideAnnotation
(
self
.
annotation
.
id
);
}).
catch
(
function
()
{
flash
.
error
(
'Failed to unhide annotation'
);
});
};
}
...
...
@@ -42,15 +50,7 @@ module.exports = {
controller
:
ModerationBannerController
,
controllerAs
:
'vm'
,
bindings
:
{
/**
* The ID of the annotation whose moderation status the banner should
* reflect.
*/
annotationId
:
'<'
,
/**
* `true` if this annotation is a reply.
*/
isReply
:
'<'
,
annotation
:
'<'
,
},
template
:
require
(
'../templates/moderation_banner.html'
),
};
src/sidebar/components/test/annotation-test.js
View file @
7c3ba4ce
...
...
@@ -145,7 +145,6 @@ describe('annotation', function() {
};
fakeAnnotationUI
=
{
isHiddenByModerator
:
sandbox
.
stub
().
returns
(
false
),
updateFlagStatus
:
sandbox
.
stub
().
returns
(
true
),
};
...
...
@@ -999,8 +998,7 @@ describe('annotation', function() {
});
it
(
'renders hidden annotations with a custom text class'
,
function
()
{
var
ann
=
fixtures
.
defaultAnnotation
();
fakeAnnotationUI
.
isHiddenByModerator
.
returns
(
true
);
var
ann
=
fixtures
.
moderatedAnnotation
({
hidden
:
true
});
var
el
=
createDirective
(
ann
).
element
;
assert
.
deepEqual
(
el
.
find
(
'markdown'
).
controller
(
'markdown'
),
{
customTextClass
:
{
...
...
src/sidebar/components/test/annotation-thread-test.js
View file @
7c3ba4ce
...
...
@@ -3,6 +3,8 @@
var
angular
=
require
(
'angular'
);
var
annotationThread
=
require
(
'../annotation-thread'
);
var
moderationBanner
=
require
(
'../moderation-banner'
);
var
fixtures
=
require
(
'../../test/annotation-fixtures'
);
var
util
=
require
(
'../../directive/test/util'
);
function
PageObject
(
element
)
{
...
...
@@ -27,10 +29,7 @@ describe('annotationThread', function () {
angular
.
module
(
'app'
,
[])
.
component
(
'annotationThread'
,
annotationThread
)
.
component
(
'moderationBanner'
,
{
bindings
:
{
annotationId
:
'<'
,
isReply
:
'<'
,
},
bindings
:
moderationBanner
.
bindings
,
});
});
...
...
@@ -184,7 +183,9 @@ describe('annotationThread', function () {
});
it
(
'renders the moderation banner'
,
function
()
{
var
ann
=
fixtures
.
moderatedAnnotation
({
flagCount
:
1
});
var
thread
=
{
annotation
:
ann
,
id
:
'123'
,
parent
:
null
,
children
:
[],
...
...
@@ -195,9 +196,6 @@ describe('annotationThread', function () {
var
moderationBanner
=
element
.
find
(
'moderation-banner'
)
.
controller
(
'moderationBanner'
);
assert
.
deepEqual
(
moderationBanner
,
{
isReply
:
false
,
annotationId
:
'123'
,
});
assert
.
deepEqual
(
moderationBanner
,
{
annotation
:
ann
});
});
});
src/sidebar/components/test/moderation-banner-test.js
View file @
7c3ba4ce
...
...
@@ -3,6 +3,9 @@
var
angular
=
require
(
'angular'
);
var
util
=
require
(
'../../directive/test/util'
);
var
fixtures
=
require
(
'../../test/annotation-fixtures'
);
var
moderatedAnnotation
=
fixtures
.
moderatedAnnotation
;
describe
(
'moderationBanner'
,
function
()
{
var
bannerEl
;
...
...
@@ -17,10 +20,8 @@ describe('moderationBanner', function () {
beforeEach
(
function
()
{
fakeAnnotationUI
=
{
flagCount
:
sinon
.
stub
().
returns
(
0
),
isHiddenByModerator
:
sinon
.
stub
().
returns
(
false
),
annotationHiddenChanged
:
sinon
.
stub
(),
hideAnnotation
:
sinon
.
stub
(),
unhideAnnotation
:
sinon
.
stub
(),
};
fakeFlash
=
{
...
...
@@ -46,75 +47,76 @@ describe('moderationBanner', function () {
});
function
createBanner
(
inputs
)
{
inputs
.
isReply
=
inputs
.
isReply
||
false
;
var
el
=
util
.
createDirective
(
document
,
'moderationBanner'
,
inputs
);
bannerEl
=
el
[
0
];
return
bannerEl
;
}
it
(
'does not display if annotation is not flagged or hidden'
,
function
()
{
fakeAnnotationUI
.
flagCount
.
returns
(
0
);
fakeAnnotationUI
.
isHiddenByModerator
.
returns
(
false
);
var
banner
=
createBanner
({
annotationId
:
'not-flagged-or-hidden-id'
});
var
banner
=
createBanner
({
annotation
:
fixtures
.
defaultAnnotation
()
});
assert
.
equal
(
banner
.
textContent
.
trim
(),
''
);
});
it
(
'displays the number of flags the annotation has received'
,
function
()
{
fakeAnnotationUI
.
flagCount
.
returns
(
10
);
var
banner
=
createBanner
({
annotation
Id
:
'flagged-id'
});
var
ann
=
fixtures
.
moderatedAnnotation
({
flagCount
:
10
}
);
var
banner
=
createBanner
({
annotation
:
ann
});
assert
.
include
(
banner
.
textContent
,
'Flagged for review x10'
);
});
it
(
'displays in a more compact form if the annotation is a reply'
,
function
()
{
fakeAnnotationUI
.
flagCount
.
returns
(
1
);
var
banner
=
createBanner
({
annotationId
:
'reply-id'
,
isReply
:
true
});
var
ann
=
Object
.
assign
(
fixtures
.
oldReply
(),
{
moderation
:
{
flag_count
:
10
,
},
});
var
banner
=
createBanner
({
annotation
:
ann
});
assert
.
ok
(
banner
.
querySelector
(
'.is-reply'
));
});
it
(
'reports if the annotation was hidden'
,
function
()
{
fakeAnnotationUI
.
isHiddenByModerator
.
returns
(
true
);
var
banner
=
createBanner
({
annotation
Id
:
'hidden-id'
});
var
ann
=
moderatedAnnotation
({
hidden
:
true
}
);
var
banner
=
createBanner
({
annotation
:
ann
});
assert
.
include
(
banner
.
textContent
,
'Hidden from users'
);
});
it
(
'hides the annotation if "Hide" is clicked'
,
function
()
{
fakeAnnotationUI
.
flagCount
.
returns
(
10
);
var
banner
=
createBanner
({
annotation
Id
:
'flagged-id'
}
);
var
ann
=
moderatedAnnotation
({
flagCount
:
10
}
);
var
banner
=
createBanner
({
annotation
:
ann
}
);
banner
.
querySelector
(
'button'
).
click
();
assert
.
calledWith
(
fakeStore
.
annotation
.
hide
,
{
id
:
'
flagged
-id'
});
assert
.
calledWith
(
fakeStore
.
annotation
.
hide
,
{
id
:
'
ann
-id'
});
});
it
(
'reports an error if hiding the annotation fails'
,
function
(
done
)
{
fakeAnnotationUI
.
flagCount
.
returns
(
10
);
var
banner
=
createBanner
({
annotation
Id
:
'flagged-id'
}
);
var
ann
=
moderatedAnnotation
({
flagCount
:
10
}
);
var
banner
=
createBanner
({
annotation
:
ann
}
);
fakeStore
.
annotation
.
hide
.
returns
(
Promise
.
reject
(
new
Error
(
'Network Error'
)));
banner
.
querySelector
(
'button'
).
click
();
setTimeout
(
function
()
{
assert
.
calledWith
(
fakeFlash
.
error
,
'
Network Error
'
);
assert
.
calledWith
(
fakeFlash
.
error
,
'
Failed to hide annotation
'
);
done
();
},
0
);
});
it
(
'unhides the annotation if "Unhide" is clicked'
,
function
()
{
fakeAnnotationUI
.
isHiddenByModerator
.
returns
(
true
);
var
banner
=
createBanner
({
annotation
Id
:
'hidden-id'
}
);
var
ann
=
moderatedAnnotation
({
hidden
:
true
}
);
var
banner
=
createBanner
({
annotation
:
ann
}
);
banner
.
querySelector
(
'button'
).
click
();
assert
.
calledWith
(
fakeStore
.
annotation
.
unhide
,
{
id
:
'
hidde
n-id'
});
assert
.
calledWith
(
fakeStore
.
annotation
.
unhide
,
{
id
:
'
an
n-id'
});
});
it
(
'reports an error if unhiding the annotation fails'
,
function
(
done
)
{
fakeAnnotationUI
.
isHiddenByModerator
.
returns
(
true
);
var
banner
=
createBanner
({
annotation
Id
:
'hidden-id'
}
);
var
ann
=
moderatedAnnotation
({
hidden
:
true
}
);
var
banner
=
createBanner
({
annotation
:
ann
}
);
fakeStore
.
annotation
.
unhide
.
returns
(
Promise
.
reject
(
new
Error
(
'Network Error'
)));
banner
.
querySelector
(
'button'
).
click
();
setTimeout
(
function
()
{
assert
.
calledWith
(
fakeFlash
.
error
,
'
Network Error
'
);
assert
.
calledWith
(
fakeFlash
.
error
,
'
Failed to unhide annotation
'
);
done
();
},
0
);
});
...
...
src/sidebar/reducers/annotations.js
View file @
7c3ba4ce
...
...
@@ -176,6 +176,26 @@ var update = {
});
return
{
annotations
:
annotations
};
},
HIDE_ANNOTATION
:
function
(
state
,
action
)
{
var
anns
=
state
.
annotations
.
map
(
function
(
ann
)
{
if
(
ann
.
id
!==
action
.
id
)
{
return
ann
;
}
return
Object
.
assign
({},
ann
,
{
hidden
:
true
});
});
return
{
annotations
:
anns
};
},
UNHIDE_ANNOTATION
:
function
(
state
,
action
)
{
var
anns
=
state
.
annotations
.
map
(
function
(
ann
)
{
if
(
ann
.
id
!==
action
.
id
)
{
return
ann
;
}
return
Object
.
assign
({},
ann
,
{
hidden
:
false
});
});
return
{
annotations
:
anns
};
},
};
var
actions
=
util
.
actionTypes
(
update
);
...
...
@@ -282,6 +302,32 @@ function updateAnchorStatus(id, tag, isOrphan) {
};
}
/**
* Update the local hidden state of an annotation.
*
* This updates an annotation to reflect the fact that it has been hidden from
* non-moderators.
*/
function
hideAnnotation
(
id
)
{
return
{
type
:
actions
.
HIDE_ANNOTATION
,
id
:
id
,
};
}
/**
* Update the local hidden state of an annotation.
*
* This updates an annotation to reflect the fact that it has been made visible
* to non-moderators.
*/
function
unhideAnnotation
(
id
)
{
return
{
type
:
actions
.
UNHIDE_ANNOTATION
,
id
:
id
,
};
}
/**
* Return all loaded annotations which have been saved to the server.
*
...
...
@@ -319,6 +365,13 @@ function findIDsForTags(state, tags) {
return
ids
;
}
/**
* Return the annotation with the given ID.
*/
function
findAnnotationByID
(
state
,
id
)
{
return
findByID
(
state
.
annotations
,
id
);
}
module
.
exports
=
{
init
:
init
,
update
:
update
,
...
...
@@ -328,10 +381,13 @@ module.exports = {
removeAnnotations
:
removeAnnotations
,
updateAnchorStatus
:
updateAnchorStatus
,
updateFlagStatus
:
updateFlagStatus
,
hideAnnotation
:
hideAnnotation
,
unhideAnnotation
:
unhideAnnotation
,
},
// Selectors
annotationExists
:
annotationExists
,
findAnnotationByID
:
findAnnotationByID
,
findIDsForTags
:
findIDsForTags
,
savedAnnotations
:
savedAnnotations
,
};
src/sidebar/reducers/index.js
View file @
7c3ba4ce
...
...
@@ -19,7 +19,6 @@
var
annotations
=
require
(
'./annotations'
);
var
frames
=
require
(
'./frames'
);
var
moderation
=
require
(
'./moderation'
);
var
selection
=
require
(
'./selection'
);
var
session
=
require
(
'./session'
);
var
viewer
=
require
(
'./viewer'
);
...
...
@@ -30,7 +29,6 @@ function init(settings) {
{},
annotations
.
init
(),
frames
.
init
(),
moderation
.
init
(),
selection
.
init
(
settings
),
session
.
init
(),
viewer
.
init
()
...
...
@@ -40,7 +38,6 @@ function init(settings) {
var
update
=
util
.
createReducer
(
Object
.
assign
(
annotations
.
update
,
frames
.
update
,
moderation
.
update
,
selection
.
update
,
session
.
update
,
viewer
.
update
...
...
src/sidebar/reducers/moderation.js
deleted
100644 → 0
View file @
8de91da2
'use strict'
;
/**
* This module defines application state and actions related to flagging and
* moderation status of annotations.
*/
var
toSet
=
require
(
'../util/array-util'
).
toSet
;
var
util
=
require
(
'./util'
);
function
init
()
{
return
{
// Map of ID -> number of times annotation has been flagged by users.
flagCounts
:
{},
// IDs of annotations hidden by a moderator.
hiddenByModerator
:
{},
};
}
/**
* Return a copy of `map` with `key` added or removed.
*
* @param {Object} map
* @param {string} key
* @param {boolean} enable
*/
function
toggle
(
map
,
key
,
enable
)
{
var
newMap
=
Object
.
assign
({},
map
);
if
(
enable
)
{
newMap
[
key
]
=
true
;
}
else
{
delete
newMap
[
key
];
}
return
newMap
;
}
var
update
=
{
ANNOTATION_HIDDEN_CHANGED
:
function
(
state
,
action
)
{
return
{
hiddenByModerator
:
toggle
(
state
.
hiddenByModerator
,
action
.
id
,
action
.
hidden
),
};
},
FETCHED_FLAG_COUNTS
:
function
(
state
,
action
)
{
return
{
flagCounts
:
action
.
flagCounts
};
},
FETCHED_HIDDEN_IDS
:
function
(
state
,
action
)
{
return
{
hiddenByModerator
:
toSet
(
action
.
ids
)
};
},
};
var
actions
=
util
.
actionTypes
(
update
);
/**
* Update the flag counts for annotations.
*
* @param {Object} flagCounts - Map from ID to count of flags
*/
function
fetchedFlagCounts
(
flagCounts
)
{
return
{
type
:
actions
.
FETCHED_FLAG_COUNTS
,
flagCounts
:
flagCounts
,
};
}
/**
* Update the set of annotations hidden by a moderator.
*
* @param {string[]} ids
*/
function
fetchedHiddenByModeratorIds
(
ids
)
{
return
{
type
:
actions
.
FETCHED_HIDDEN_IDS
,
ids
:
ids
,
};
}
/**
* An annotation was hidden or unhidden by a moderator.
*
* @param {string} id
* @param {boolean} hidden
*/
function
annotationHiddenChanged
(
id
,
hidden
)
{
return
{
type
:
actions
.
ANNOTATION_HIDDEN_CHANGED
,
id
:
id
,
hidden
:
hidden
,
};
}
/**
* Return the number of items an annotation with a given `id` has been flagged
* by members of the annotation's group.
*
* @param {Object} state
* @param {string} id
*/
function
flagCount
(
state
,
id
)
{
return
state
.
flagCounts
[
id
]
||
0
;
}
/**
* Return `true` if an annotation was hidden by a moderator.
*
* @param {Object} state
* @param {string} id
*/
function
isHiddenByModerator
(
state
,
id
)
{
return
!!
state
.
hiddenByModerator
[
id
];
}
module
.
exports
=
{
init
:
init
,
update
:
update
,
actions
:
{
annotationHiddenChanged
:
annotationHiddenChanged
,
fetchedFlagCounts
:
fetchedFlagCounts
,
fetchedHiddenByModeratorIds
:
fetchedHiddenByModeratorIds
,
},
// Selectors
isHiddenByModerator
:
isHiddenByModerator
,
flagCount
:
flagCount
,
};
src/sidebar/reducers/test/annotations-test.js
View file @
7c3ba4ce
'use strict'
;
var
redux
=
require
(
'redux'
);
// `.default` is needed because 'redux-thunk' is built as an ES2015 module
var
thunk
=
require
(
'redux-thunk'
).
default
;
var
annotations
=
require
(
'../annotations'
);
var
fixtures
=
require
(
'../../test/annotation-fixtures'
);
var
util
=
require
(
'../util'
);
var
actions
=
annotations
.
actions
;
/**
* Create a Redux store which only handles annotation actions.
*/
function
createStore
()
{
// Thunk middleware is needed for the ADD_ANNOTATIONS action.
var
enhancer
=
redux
.
applyMiddleware
(
thunk
);
var
reducer
=
util
.
createReducer
(
annotations
.
update
);
return
redux
.
createStore
(
reducer
,
annotations
.
init
(),
enhancer
);
}
// Tests for most of the functionality in reducers/annotations.js are currently
// in the tests for the whole Redux store
...
...
@@ -37,4 +54,26 @@ describe('annotations reducer', function () {
assert
.
deepEqual
(
findIDsForTags
(
state
,
[
't1'
]),
[]);
});
});
describe
(
'#hideAnnotation'
,
function
()
{
it
(
'sets the `hidden` state to `true`'
,
function
()
{
var
store
=
createStore
();
var
ann
=
fixtures
.
moderatedAnnotation
({
hidden
:
false
});
store
.
dispatch
(
actions
.
addAnnotations
([
ann
]));
store
.
dispatch
(
actions
.
hideAnnotation
(
ann
.
id
));
var
storeAnn
=
annotations
.
findAnnotationByID
(
store
.
getState
(),
ann
.
id
);
assert
.
equal
(
storeAnn
.
hidden
,
true
);
});
});
describe
(
'#unhideAnnotation'
,
function
()
{
it
(
'sets the `hidden` state to `false`'
,
function
()
{
var
store
=
createStore
();
var
ann
=
fixtures
.
moderatedAnnotation
({
hidden
:
true
});
store
.
dispatch
(
actions
.
addAnnotations
([
ann
]));
store
.
dispatch
(
actions
.
unhideAnnotation
(
ann
.
id
));
var
storeAnn
=
annotations
.
findAnnotationByID
(
store
.
getState
(),
ann
.
id
);
assert
.
equal
(
storeAnn
.
hidden
,
false
);
});
});
});
src/sidebar/reducers/test/moderation-test.js
deleted
100644 → 0
View file @
8de91da2
'use strict'
;
var
moderation
=
require
(
'../moderation'
);
var
util
=
require
(
'../util'
);
var
init
=
moderation
.
init
;
var
actions
=
moderation
.
actions
;
var
update
=
util
.
createReducer
(
moderation
.
update
);
describe
(
'moderation reducer'
,
function
()
{
describe
(
'#fetchedFlagCounts'
,
function
()
{
it
(
'updates the flag counts'
,
function
()
{
var
state
=
update
(
init
(),
actions
.
fetchedFlagCounts
({
'flagged-id'
:
1
,
'also-flagged-id'
:
2
}));
assert
.
deepEqual
(
state
.
flagCounts
,
{
'flagged-id'
:
1
,
'also-flagged-id'
:
2
});
});
});
describe
(
'#flagCount'
,
function
()
{
it
(
'returns the number of times the annotation was flagged'
,
function
()
{
var
state
=
update
(
init
(),
actions
.
fetchedFlagCounts
({
'flagged-id'
:
1
,
'also-flagged-id'
:
2
}));
assert
.
equal
(
moderation
.
flagCount
(
state
,
'flagged-id'
),
1
);
assert
.
equal
(
moderation
.
flagCount
(
state
,
'not-flagged-id'
),
0
);
});
});
describe
(
'#fetchedHiddenByModeratorIds'
,
function
()
{
it
(
'updates the set of moderated IDs'
,
function
()
{
var
state
=
update
(
init
(),
actions
.
fetchedHiddenByModeratorIds
([
'hidden-id'
]));
assert
.
deepEqual
(
state
.
hiddenByModerator
,
{
'hidden-id'
:
true
});
});
});
describe
(
'#isHiddenByModerator'
,
function
()
{
var
state
=
update
(
init
(),
actions
.
fetchedHiddenByModeratorIds
([
'hidden-id'
]));
it
(
'returns true if the annotation was hidden'
,
function
()
{
assert
.
isTrue
(
moderation
.
isHiddenByModerator
(
state
,
'hidden-id'
));
});
it
(
'returns false if the annotation was not hidden'
,
function
()
{
assert
.
isFalse
(
moderation
.
isHiddenByModerator
(
state
,
'not-hidden-id'
));
});
});
describe
(
'#annotationHiddenChanged'
,
function
()
{
it
(
'alters the hidden status of the annotation'
,
function
()
{
var
state
=
update
(
init
(),
actions
.
fetchedHiddenByModeratorIds
([
'hidden-id'
]));
state
=
update
(
state
,
actions
.
annotationHiddenChanged
(
'hidden-id'
,
false
));
assert
.
isFalse
(
moderation
.
isHiddenByModerator
(
state
,
'hidden-id'
));
});
});
});
src/sidebar/store.js
View file @
7c3ba4ce
...
...
@@ -171,6 +171,8 @@ function store($http, $q, auth, settings) {
get
:
apiCall
(
'annotation.read'
),
update
:
apiCall
(
'annotation.update'
),
flag
:
apiCall
(
'annotation.flag'
),
hide
:
apiCall
(
'annotation.hide'
),
unhide
:
apiCall
(
'annotation.unhide'
),
},
profile
:
{
read
:
apiCall
(
'profile.read'
),
...
...
src/sidebar/templates/annotation_thread.html
View file @
7c3ba4ce
...
...
@@ -10,8 +10,7 @@
<div
class=
"annotation-thread__thread-line"
></div>
</div>
<div
class=
"annotation-thread__content"
>
<moderation-banner
is-reply=
"!vm.isTopLevelThread()"
annotation-id=
"vm.thread.id"
>
<moderation-banner
annotation=
"vm.thread.annotation"
>
</moderation-banner>
<annotation
ng-class=
"vm.annotationClasses()"
annotation=
"vm.thread.annotation"
...
...
src/sidebar/templates/moderation_banner.html
View file @
7c3ba4ce
...
...
@@ -2,7 +2,7 @@
ng-if=
"vm.flagCount() > 0 || vm.isHidden()"
ng-class=
"{'is-flagged': vm.flagCount() > 0,
'is-hidden': vm.isHidden(),
'is-reply': vm.isReply}"
>
'is-reply': vm.isReply
()
}"
>
<span
ng-if=
"vm.flagCount() > 0 && !vm.isHidden()"
>
Flagged for review x{{ vm.flagCount() }}
</span>
...
...
src/sidebar/test/annotation-fixtures.js
View file @
7c3ba4ce
...
...
@@ -137,9 +137,32 @@ function oldReply() {
};
}
/**
* @typedef ModerationState
* @property {boolean} hidden
* @property {number} flagCount
*/
/**
* Return an annotation with the given moderation state.
*
* @param {ModerationState} modInfo
*/
function
moderatedAnnotation
(
modInfo
)
{
return
Object
.
assign
(
defaultAnnotation
(),
{
id
:
'ann-id'
,
hidden
:
!!
modInfo
.
hidden
,
moderation
:
{
flag_count
:
modInfo
.
flagCount
||
0
,
},
});
}
module
.
exports
=
{
defaultAnnotation
:
defaultAnnotation
,
publicAnnotation
:
publicAnnotation
,
moderatedAnnotation
:
moderatedAnnotation
,
newAnnotation
:
newAnnotation
,
newEmptyAnnotation
:
newEmptyAnnotation
,
newHighlight
:
newHighlight
,
...
...
src/sidebar/test/annotation-metadata-test.js
View file @
7c3ba4ce
...
...
@@ -316,4 +316,17 @@ describe('annotation-metadata', function () {
assert
.
isFalse
(
isWaitingToAnchor
(
pending
));
});
});
describe
(
'.flagCount'
,
function
()
{
var
flagCount
=
annotationMetadata
.
flagCount
;
it
(
'returns 0 if the user is not a moderator'
,
function
()
{
assert
.
equal
(
flagCount
(
fixtures
.
defaultAnnotation
()),
0
);
});
it
(
'returns the flag count if present'
,
function
()
{
var
ann
=
fixtures
.
moderatedAnnotation
({
flagCount
:
10
});
assert
.
equal
(
flagCount
(
ann
),
10
);
});
});
});
src/sidebar/test/store-test.js
View file @
7c3ba4ce
...
...
@@ -51,6 +51,9 @@ describe('store', function () {
store
=
_store_
;
$httpBackend
.
expectGET
(
'http://example.com/api'
).
respond
({
// Return an API route directory.
// This should mirror the structure (but not the exact URLs) of
// https://hypothes.is/api/.
links
:
{
annotation
:
{
create
:
{
...
...
@@ -70,6 +73,14 @@ describe('store', function () {
method
:
'PUT'
,
url
:
'http://example.com/api/annotations/:id/flag'
,
},
hide
:
{
method
:
'PUT'
,
url
:
'http://example.com/api/annotations/:id/hide'
,
},
unhide
:
{
method
:
'DELETE'
,
url
:
'http://example.com/api/annotations/:id/hide'
,
},
},
search
:
{
method
:
'GET'
,
...
...
@@ -139,6 +150,30 @@ describe('store', function () {
$httpBackend
.
flush
();
});
it
(
'hides an annotation'
,
function
(
done
)
{
store
.
annotation
.
hide
({
id
:
'an-id'
}).
then
(
function
()
{
done
();
});
$httpBackend
.
expectPUT
(
'http://example.com/api/annotations/an-id/hide'
)
.
respond
(
function
()
{
return
[
204
,
{},
{}];
});
$httpBackend
.
flush
();
});
it
(
'unhides an annotation'
,
function
(
done
)
{
store
.
annotation
.
unhide
({
id
:
'an-id'
}).
then
(
function
()
{
done
();
});
$httpBackend
.
expectDELETE
(
'http://example.com/api/annotations/an-id/hide'
)
.
respond
(
function
()
{
return
[
204
,
{},
{}];
});
$httpBackend
.
flush
();
});
it
(
'removes internal properties before sending data to the server'
,
function
(
done
)
{
var
annotation
=
{
$highlight
:
true
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment