mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-10 08:21:21 +00:00
updates security specification on datasets to obtain data for gdpr related to each dataset
This commit is contained in:
parent
8388d41fa1
commit
d9eb5c4d11
@ -1,6 +1,6 @@
|
|||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import isTrackingHeaderField from 'wherehows-web/utils/validators/tracking-headers';
|
import isTrackingHeaderField from 'wherehows-web/utils/validators/tracking-headers';
|
||||||
import { defaultFieldDataTypeClassification, classifiers } from 'wherehows-web/constants';
|
import { defaultFieldDataTypeClassification, classifiers, datasetClassifiers } from 'wherehows-web/constants';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
get,
|
get,
|
||||||
@ -14,15 +14,29 @@ const {
|
|||||||
String: { htmlSafe }
|
String: { htmlSafe }
|
||||||
} = Ember;
|
} = Ember;
|
||||||
|
|
||||||
// String constant identifying the classified fields on the security spec
|
/**
|
||||||
|
* String constant identifying the classified fields on the security spec
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
const sourceClassificationKey = 'securitySpecification.classification';
|
const sourceClassificationKey = 'securitySpecification.classification';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String constant identifying the datasetClassification on the security spec
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
const datasetClassificationKey = 'securitySpecification.datasetClassification';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of logical types / field level data types
|
* List of logical types / field level data types
|
||||||
* https://iwww.corp.linkedin.com/wiki/cf/display/DWH/List+of+Metadata+for+Data+Sets
|
* https://iwww.corp.linkedin.com/wiki/cf/display/DWH/List+of+Metadata+for+Data+Sets
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
const logicalTypes = Object.keys(defaultFieldDataTypeClassification);
|
const logicalTypes = Object.keys(defaultFieldDataTypeClassification);
|
||||||
|
/**
|
||||||
|
* A list of available keys for the datasetClassification map on the security specification
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
const datasetClassifiersKeys = Object.keys(datasetClassifiers);
|
||||||
|
|
||||||
// TODO: DSS-6671 Extract to constants module
|
// TODO: DSS-6671 Extract to constants module
|
||||||
const successUpdating = 'Your changes have been successfully saved!';
|
const successUpdating = 'Your changes have been successfully saved!';
|
||||||
@ -69,6 +83,24 @@ export default Component.extend({
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computed property that is dependent on all the keys in the datasetClassification map
|
||||||
|
* Returns a new map of datasetClassificationKey: String-> Object.<Boolean|undefined,String>
|
||||||
|
* @type {Ember.computed}
|
||||||
|
*/
|
||||||
|
datasetClassification: computed(`${datasetClassificationKey}.{${datasetClassifiersKeys.join(',')}}`, function() {
|
||||||
|
const sourceDatasetClassification = getWithDefault(this, datasetClassificationKey, {});
|
||||||
|
|
||||||
|
return Object.keys(datasetClassifiers).reduce((datasetClassification, classifier) => {
|
||||||
|
datasetClassification[classifier] = {
|
||||||
|
value: sourceDatasetClassification[classifier],
|
||||||
|
label: datasetClassifiers[classifier]
|
||||||
|
};
|
||||||
|
|
||||||
|
return datasetClassification;
|
||||||
|
}, {});
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a lookup table of fieldNames to classification
|
* Creates a lookup table of fieldNames to classification
|
||||||
* Also, the expectation is that the association from fieldName -> classification
|
* Also, the expectation is that the association from fieldName -> classification
|
||||||
@ -76,9 +108,7 @@ export default Component.extend({
|
|||||||
* in the lookup assignment
|
* in the lookup assignment
|
||||||
*/
|
*/
|
||||||
fieldNameToClass: computed(
|
fieldNameToClass: computed(
|
||||||
`${sourceClassificationKey}.confidential.[]`,
|
`${sourceClassificationKey}.{confidential,limitedDistribution,highlyConfidential}.[]`,
|
||||||
`${sourceClassificationKey}.limitedDistribution.[]`,
|
|
||||||
`${sourceClassificationKey}.highlyConfidential.[]`,
|
|
||||||
function () {
|
function () {
|
||||||
const sourceClasses = getWithDefault(this, sourceClassificationKey, []);
|
const sourceClasses = getWithDefault(this, sourceClassificationKey, []);
|
||||||
// Creates a lookup table of fieldNames to classification
|
// Creates a lookup table of fieldNames to classification
|
||||||
@ -105,9 +135,7 @@ export default Component.extend({
|
|||||||
* securitySpecification.classification or null if not found
|
* securitySpecification.classification or null if not found
|
||||||
*/
|
*/
|
||||||
classificationDataFields: computed(
|
classificationDataFields: computed(
|
||||||
`${sourceClassificationKey}.confidential.[]`,
|
`${sourceClassificationKey}.{confidential,limitedDistribution,highlyConfidential}.[]`,
|
||||||
`${sourceClassificationKey}.limitedDistribution.[]`,
|
|
||||||
`${sourceClassificationKey}.highlyConfidential.[]`,
|
|
||||||
'schemaFieldNamesMappedToDataTypes',
|
'schemaFieldNamesMappedToDataTypes',
|
||||||
function () {
|
function () {
|
||||||
// Set default or if already in policy, retrieve current values from
|
// Set default or if already in policy, retrieve current values from
|
||||||
@ -330,6 +358,16 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the source object representing the current datasetClassification map
|
||||||
|
* @param {String} classifier the property on the datasetClassification to update
|
||||||
|
* @param {Boolean} value flag indicating if this dataset contains member data for the specified classifier
|
||||||
|
*/
|
||||||
|
didChangeDatasetClassification(classifier, value) {
|
||||||
|
const sourceDatasetClassification = getWithDefault(this, datasetClassificationKey, {});
|
||||||
|
return set(sourceDatasetClassification, classifier, value);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify controller to propagate changes
|
* Notify controller to propagate changes
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
|
|||||||
24
wherehows-web/app/constants/dataset-classification.js
Normal file
24
wherehows-web/app/constants/dataset-classification.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const datasetClassifiers = {
|
||||||
|
CONNECTIONS_FOLLOWERS_FOLLOWING: 'Connections + Followers + Following',
|
||||||
|
PROFILE_DATA: 'Profile Data',
|
||||||
|
MESSAGING_DATA: 'Messaging Data (Metadata + Content)',
|
||||||
|
THIRD_PARTY_INTEGRATIONS: 'Third Party Integrations In Use',
|
||||||
|
ACTIVITY: 'Activity (Newsfeed Posts + Shares + Likes)',
|
||||||
|
JOB_APPLICATION_FLOW_DATA: 'Job Application Flow Data (Job Application + AWLI + Resumes + Application Answers)',
|
||||||
|
ENTERPRISE_PRODUCT_DATA: 'Enterprise Product Data',
|
||||||
|
ACCOUNT_STATUS: 'Account Status',
|
||||||
|
ADDRESS_BOOK_IMPORT_DATA: 'Address Book Import Data',
|
||||||
|
MICROSOFT_DATA: 'Data from Microsoft',
|
||||||
|
SUBSIDIARY_DATA: 'Data from companies LinkedIn acquired (Lynda, Slideshare, Connectifier, Bizo, etcetera)',
|
||||||
|
THIRD_PARTY_DATA: 'Data from Third-party Integrations',
|
||||||
|
DEVICE_DATA: 'Device Data',
|
||||||
|
SEARCH_HISTORY: 'Search History',
|
||||||
|
COURSE_VIEWING_HISTORY: 'Course Viewing History',
|
||||||
|
WVMP: "Who's Viewed My Profile",
|
||||||
|
PROFILE_VIEWS_BY_ME: 'Profile Views (by me)',
|
||||||
|
ADVERTISING_DATA: 'Advertising related (LMS) Data',
|
||||||
|
USAGE_ERROR_CONNECTIVITY_DATA: 'Usage, Error Reporting, Connectivity Data',
|
||||||
|
OTHER_CLICKSTREAM_BROWSING_DATA: 'Other Clickstream Data + Browsing history'
|
||||||
|
};
|
||||||
|
|
||||||
|
export { datasetClassifiers };
|
||||||
@ -1 +1,2 @@
|
|||||||
export * from 'wherehows-web/constants/metadata-acquisition';
|
export * from 'wherehows-web/constants/metadata-acquisition';
|
||||||
|
export * from 'wherehows-web/constants/dataset-classification';
|
||||||
|
|||||||
@ -1,14 +1,9 @@
|
|||||||
$user-name-width: 170px;
|
$user-name-width: 170px;
|
||||||
$zebra: set-color(grey, light);
|
|
||||||
|
|
||||||
.ownership-actions {
|
.ownership-actions {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dataset-author-row:nth-child(odd) {
|
|
||||||
background-color: tint($zebra, 80%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dataset-author-cell {
|
.dataset-author-cell {
|
||||||
max-width: $user-name-width;
|
max-width: $user-name-width;
|
||||||
width: $user-name-width;
|
width: $user-name-width;
|
||||||
|
|||||||
@ -27,3 +27,25 @@
|
|||||||
background-color: tint(set-color(green, green5), 65%);
|
background-color: tint(set-color(green, green5), 65%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wraps a status notification icon for a given dataset
|
||||||
|
.dataset-tag-container {
|
||||||
|
width: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A notification that a dataset contains a tag
|
||||||
|
.dataset-tagged {
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
color: set-color(green, green5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A notification that a dataset does not contains a tag
|
||||||
|
.dataset-not-tagged {
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
color: set-color(red, red5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
restyle-var(header-color): set-color(grey, light),
|
restyle-var(header-color): set-color(grey, light),
|
||||||
restyle-var(horizontal-padding): 10px,
|
restyle-var(horizontal-padding): 10px,
|
||||||
restyle-var(font-size): 16px,
|
restyle-var(font-size): 16px,
|
||||||
|
restyle-var(zebra): tint(set-color(grey, light), 80%),
|
||||||
border-collapse: collapse,
|
border-collapse: collapse,
|
||||||
border-spacing: 0,
|
border-spacing: 0,
|
||||||
text-align: left,
|
text-align: left,
|
||||||
@ -30,6 +31,11 @@
|
|||||||
restyle-modifiers: (
|
restyle-modifiers: (
|
||||||
'with a border': (
|
'with a border': (
|
||||||
border: 1px solid restyle-var(border-color)
|
border: 1px solid restyle-var(border-color)
|
||||||
|
),
|
||||||
|
'with stripped rows': (
|
||||||
|
'& tr:nth-child(odd)': (
|
||||||
|
background-color: restyle-var(zebra)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
@ -40,4 +46,8 @@
|
|||||||
&--bordered {
|
&--bordered {
|
||||||
@include restyle(table with a border);
|
@include restyle(table with a border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--stripped {
|
||||||
|
@include restyle(table with stripped rows);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="alert alert-success" role="alert">{{actionMessage}}</div>
|
<div class="alert alert-success" role="alert">{{actionMessage}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<table class="nacho-table nacho-table--bordered">
|
<table class="nacho-table nacho-table--bordered nacho-table--stripped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>User Name</th>
|
<th>User Name</th>
|
||||||
@ -111,8 +111,8 @@
|
|||||||
<td>{{owner.idType}}</td>
|
<td>{{owner.idType}}</td>
|
||||||
<td>{{owner.source}}</td>
|
<td>{{owner.source}}</td>
|
||||||
<td class="dataset-author-cell__owner-last-mod">
|
<td class="dataset-author-cell__owner-last-mod">
|
||||||
{{!-- e.g Jul 18th '16, 11:11 am --}}
|
{{!-- e.g Jul 18th 2016, 11:11 am --}}
|
||||||
{{moment-calendar owner.modifiedTime sameElse="MMM Do 'YY, h:m a"}}
|
{{moment-calendar owner.modifiedTime sameElse="MMM Do YYYY, h:mm a"}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ember-selector
|
{{ember-selector
|
||||||
|
|||||||
@ -26,6 +26,73 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<section class="metadata-prompt">
|
||||||
|
<header class="metadata-prompt__header">
|
||||||
|
<p>
|
||||||
|
This dataset contains the following types of Member data:
|
||||||
|
|
||||||
|
<!--TODO: DSS-6716-->
|
||||||
|
<!-- DRY out with wrapper component that takes the link as an attribute-->
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="https://iwww.corp.linkedin.com/wiki/cf/display/DWH/List+of+Metadata+for+Data+Sets">
|
||||||
|
<sup>
|
||||||
|
More Info
|
||||||
|
|
||||||
|
<span class="glyphicon glyphicon-question-sign"
|
||||||
|
title="More information on Dataset classification with examples"></span>
|
||||||
|
</sup>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<table class="nacho-table nacho-table--bordered nacho-table--stripped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Dataset Content Type</th>
|
||||||
|
<th>Is this type of member data contained in this dataset?</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each-in datasetClassification as |classification props|}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{props.label}}
|
||||||
|
|
||||||
|
<span class="dataset-tag-container">
|
||||||
|
{{#if (eq props.value true)}}
|
||||||
|
<i class="glyphicon glyphicon-ok dataset-tagged" title="{{props.label}} is in dataset"></i>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if (eq props.value false)}}
|
||||||
|
<i class="glyphicon glyphicon-remove dataset-not-tagged" title="{{props.label}} is not in dataset"></i>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{#radio-button-composer
|
||||||
|
value=true
|
||||||
|
name=classification
|
||||||
|
groupValue=(readonly props.value)
|
||||||
|
changed=(action "didChangeDatasetClassification")}}
|
||||||
|
Yes
|
||||||
|
{{/radio-button-composer}}
|
||||||
|
{{#radio-button-composer
|
||||||
|
value=false
|
||||||
|
name=classification
|
||||||
|
groupValue=(readonly props.value)
|
||||||
|
changed=(action "didChangeDatasetClassification")}}
|
||||||
|
No
|
||||||
|
{{/radio-button-composer}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/each-in}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
{{!--Renders content of `hiddenTrackingFields` to the viewer if the dataset contains hidden tracking fields--}}
|
{{!--Renders content of `hiddenTrackingFields` to the viewer if the dataset contains hidden tracking fields--}}
|
||||||
{{#if containsHiddenTrackingFields}}
|
{{#if containsHiddenTrackingFields}}
|
||||||
<div class="alert alert-info" role="alert">
|
<div class="alert alert-info" role="alert">
|
||||||
|
|||||||
@ -31,7 +31,8 @@ const createSecuritySpecification = id => {
|
|||||||
datasetId: id,
|
datasetId: id,
|
||||||
geographicAffinity: { affinity: '' },
|
geographicAffinity: { affinity: '' },
|
||||||
recordOwnerType: '',
|
recordOwnerType: '',
|
||||||
retentionPolicy: { retentionType: '' }
|
retentionPolicy: { retentionType: '' },
|
||||||
|
datasetClassification: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
return JSON.parse(JSON.stringify(securitySpecification));
|
return JSON.parse(JSON.stringify(securitySpecification));
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Matches a url string with a `urn` query. urn query with letters or underscore segment of any length greater
|
* Matches a url string with a `urn` query. urn query with letters or underscore segment of any length greater
|
||||||
* than 1 followed by colon and 3 forward slashes and a segment containing letters, _ or /, or none
|
* than 1 followed by colon and 3 forward slashes and a segment containing letters, {, }, _ or /, or none
|
||||||
* The value following the urn key is retained
|
* The value following the urn key is retained
|
||||||
* @type {RegExp}
|
* @type {RegExp}
|
||||||
*/
|
*/
|
||||||
const urnRegex = /([a-z_]+):\/{3}([a-z0-9_\-\/]*)/i;
|
const urnRegex = /([a-z_]+):\/{3}([a-z0-9_\-\/\{\}]*)/i;
|
||||||
/**
|
/**
|
||||||
* Asserts that a provided string matches the urn pattern above
|
* Asserts that a provided string matches the urn pattern above
|
||||||
* @param {String} candidateUrn the string to test on
|
* @param {String} candidateUrn the string to test on
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user