Skip to content

Commit

Permalink
Highlight overlapping license pattern matches in green
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Aug 26, 2024
1 parent 923bb3e commit a965dab
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 84 deletions.
31 changes: 22 additions & 9 deletions assets/vue/EditSnippet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
</div>
<form :action="this.decisionUrl" method="POST">
<input type="hidden" name="package" :value="this.package.id" v-if="this.package !== null" />
<input type="hidden" name="highlighted" :value="this.highlighted" />
<input type="hidden" name="highlighted-keywords" :value="this.highlightedKeywords" />
<input type="hidden" name="highlighted-licenses" :value="this.highlightedLicenses" />
<input type="hidden" name="edited" :value="this.edited" />
<input type="hidden" name="hash" :value="this.hash" />
<input type="hidden" name="from" :value="this.from" />
Expand Down Expand Up @@ -197,7 +198,8 @@ export default {
editor: null,
from: params.from ?? null,
hash: params.hash ?? null,
highlighted: '',
highlightedKeywords: '',
highlightedLicenses: '',
keywords: {},
license: '',
licenseFocused: false,
Expand All @@ -208,6 +210,7 @@ export default {
risk: 1,
trademark: false
},
matches: {},
package: null,
patternText: '',
results: [],
Expand Down Expand Up @@ -267,6 +270,7 @@ export default {
if (this.package !== null) this.package.packageUrl = `/reviews/details/${this.package.id}`;
this.patternText = snippet.text;
this.startLine = snippet.sline;
this.matches = snippet.matches;
this.keywords = snippet.keywords;
this.licenses = data.licenses;
this.suggestions = Object.keys(this.licenses);
Expand All @@ -277,13 +281,16 @@ export default {
getHighlightedLines() {
const cm = this.editor;
const count = cm.lineCount();
const lines = [];
const keywordLines = [];
const licenseLines = [];
for (let i = 0; i < count; i++) {
const line = cm.getLineHandle(i);
const bgClass = line.bgClass ?? '';
if (bgClass.match('found-pattern')) lines.push(i);
if (bgClass.match('keyword-line')) keywordLines.push(i);
if (bgClass.match('license-line')) licenseLines.push(i);
}
this.highlighted = lines.join(',');
this.highlightedKeywords = keywordLines.join(',');
this.highlightedLicenses = licenseLines.join(',');
},
setupCodeMirror() {
const cm = CodeMirror.fromTextArea(this.$refs.patternText, {
Expand All @@ -308,9 +315,12 @@ export default {
}
});
const keywords = this.keywords;
for (const [line, pattern] of Object.entries(keywords)) {
cm.addLineClass(parseInt(line), 'background', `found-pattern pattern-${pattern}`);
for (const [line, pattern] of Object.entries(this.matches)) {
cm.addLineClass(parseInt(line), 'background', `license-line found-pattern pattern-${pattern}`);
}
for (const [line, pattern] of Object.entries(this.keywords)) {
cm.addLineClass(parseInt(line), 'background', `keyword-line found-pattern pattern-${pattern}`);
}
this.editor = cm;
Expand Down Expand Up @@ -349,9 +359,12 @@ export default {
.autocomplete-item:hover {
background-color: rgba(13, 110, 253, 0.25);
}
.found-pattern {
.keyword-line {
background-color: #fdd !important;
}
.license-line {
background-color: #dfd !important;
}
.closest-container {
margin-top: 1rem;
Expand Down
21 changes: 14 additions & 7 deletions assets/vue/ProposedPatterns.vue
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,15 @@ export default {
change.editUrl = `${change.editUrl}?hash=${change.token_hexsum}&from=${change.data.from}`;
}
const highlighted = change.data.highlighted ?? [];
const highlightedKeywords = change.data.highlighted_keywords ?? [];
const highlightedLicenses = change.data.highlighted_licenses ?? [];
let num = 0;
const lines = [];
for (const line of change.data.pattern.split('\n')) {
const isHighlighted = highlighted.includes(num.toString());
lines.push({num: ++num, text: line, highlighted: isHighlighted});
for (const text of change.data.pattern.split('\n')) {
const isKeyword = highlightedKeywords.includes(num.toString());
const isLicense = highlightedLicenses.includes(num.toString());
const highlighted = isLicense ? 'license' : isKeyword ? 'keyword' : null;
lines.push({num: ++num, text, highlighted});
}
change.lines = lines;
Expand All @@ -222,8 +225,9 @@ export default {
},
getClassForLine(line) {
return {
'change-highlighted-line code': line.highlighted,
code: !line.highlighted
'change-keyword-line code': line.highlighted === 'keyword',
'change-license-line code': line.highlighted === 'license',
code: line.highlighted === null
};
},
getClassForCode(change) {
Expand Down Expand Up @@ -334,9 +338,12 @@ export default {
color: rgba(27, 31, 35, 0.3);
user-select: none;
}
.change-highlighted-line {
.change-keyword-line {
background-color: #ffebe9;
}
.change-license-line {
background-color: #ebffe9;
}
.change-code-ignore {
background: repeating-linear-gradient(-45deg, #ffebe9, #ffebe9 1px, #fff 1px, #fff 5px);
}
Expand Down
3 changes: 2 additions & 1 deletion docs/Contributors.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ attention of a lawyer.

With the snippet editor you can make small adjustments to the soon to be license pattern. Remove sections of text that
are irrelevant and replace company names or dates with placeholders like `$SKIP7` (this one will skip up to `7` words).
Just make sure to include all red lines, because these are the ones that include keyword matches.
Just make sure to include all red lines, because these are the ones that include keyword matches. Green lines indicate
an overlapping match for an existing license pattern and can be safely removed.

Finding the right balance between larger and smaller patterns is not an exact science and requires some experience. If
none of the red lines contain any actual legal text, or if all legal text appears outside the red lines, that would be
Expand Down
46 changes: 25 additions & 21 deletions lib/Cavil/Controller/Snippet.pm
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ sub _propose_pattern ($self, $validation) {
$validation->required('pattern');
$validation->required('risk')->num;
$validation->optional('edited');
$validation->optional('highlighted', 'comma_separated');
$validation->optional('highlighted-keywords', 'comma_separated');
$validation->optional('highlighted-licenses', 'comma_separated');
$validation->optional('package');
$validation->optional('patent');
$validation->optional('trademark');
Expand All @@ -219,17 +220,18 @@ sub _propose_pattern ($self, $validation) {

my $user_id = $self->users->id_for_login($self->current_user);
my $result = $self->patterns->propose_create(
snippet => $snippet->{id},
pattern => $pattern,
highlighted => $validation->every_param('highlighted'),
edited => $validation->param('edited'),
license => $validation->param('license'),
risk => $validation->param('risk'),
package => $validation->param('package'),
patent => $validation->param('patent'),
trademark => $validation->param('trademark'),
export_restricted => $validation->param('export_restricted'),
owner => $user_id
snippet => $snippet->{id},
pattern => $pattern,
highlighted_keywords => $validation->every_param('highlighted-keywords'),
highlighted_licenses => $validation->every_param('highlighted-licenses'),
edited => $validation->param('edited'),
license => $validation->param('license'),
risk => $validation->param('risk'),
package => $validation->param('package'),
patent => $validation->param('patent'),
trademark => $validation->param('trademark'),
export_restricted => $validation->param('export_restricted'),
owner => $user_id
);

return $self->render(
Expand All @@ -248,7 +250,8 @@ sub _propose_ignore ($self, $validation) {
$validation->required('from');
$validation->required('pattern');
$validation->required('edited');
$validation->optional('highlighted', 'comma_separated');
$validation->optional('highlighted-keywords', 'comma_separated');
$validation->optional('highlighted-licenses', 'comma_separated');
$validation->optional('package');
return $self->reply->json_validation_error if $validation->has_error;

Expand All @@ -257,14 +260,15 @@ sub _propose_ignore ($self, $validation) {

my $user_id = $self->users->id_for_login($self->current_user);
my $result = $self->patterns->propose_ignore(
snippet => $self->param('id'),
hash => $validation->param('hash'),
from => $validation->param('from'),
pattern => $validation->param('pattern'),
highlighted => $validation->every_param('highlighted'),
edited => $edited,
package => $validation->param('package'),
owner => $user_id
snippet => $self->param('id'),
hash => $validation->param('hash'),
from => $validation->param('from'),
pattern => $validation->param('pattern'),
highlighted_keywords => $validation->every_param('highlighted-keywords'),
highlighted_licenses => $validation->every_param('highlighted-licenses'),
edited => $edited,
package => $validation->param('package'),
owner => $user_id
);

return $self->render(status => 409, error => 'Conflicting ignore pattern already exists') if $result->{conflict};
Expand Down
34 changes: 18 additions & 16 deletions lib/Cavil/Model/Patterns.pm
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,17 @@ sub propose_create ($self, %args) {
action => 'create_pattern',
data => {
-json => {
snippet => $args{snippet},
pattern => $pattern,
highlighted => $args{highlighted},
edited => $args{edited} // '0',
license => $license,
risk => $risk,
package => $args{package},
patent => $args{patent} // '0',
trademark => $args{trademark} // '0',
export_restricted => $args{export_restricted} // '0'
snippet => $args{snippet},
pattern => $pattern,
highlighted_keywords => $args{highlighted_keywords},
highlighted_licenses => $args{highlighted_licenses},
edited => $args{edited} // '0',
license => $license,
risk => $risk,
package => $args{package},
patent => $args{patent} // '0',
trademark => $args{trademark} // '0',
export_restricted => $args{export_restricted} // '0'
}
},
owner => $args{owner},
Expand All @@ -319,12 +320,13 @@ sub propose_ignore ($self, %args) {
action => 'create_ignore',
data => {
-json => {
snippet => $args{snippet},
from => $args{from},
pattern => $args{pattern},
highlighted => $args{highlighted},
edited => $args{edited} // '0',
package => $args{package},
snippet => $args{snippet},
from => $args{from},
pattern => $args{pattern},
highlighted_keywords => $args{highlighted_keywords},
highlighted_licenses => $args{highlighted_licenses},
edited => $args{edited} // '0',
package => $args{package},
}
},
owner => $args{owner},
Expand Down
7 changes: 4 additions & 3 deletions lib/Cavil/Model/Snippets.pm
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ sub with_context ($self, $id) {
my $text = $snippet->{text};
my $sline = 1;
my $package = undef;
my $matches = {};
my $keywords = {};

my $db = $self->pg->db;
Expand All @@ -156,14 +157,14 @@ sub with_context ($self, $id) {
$example->{eline}
)->hashes;
for my $pattern (@$patterns) {
next if $pattern->{license};
my $map = $pattern->{license} ? $matches : $keywords;
for (my $line = $pattern->{sline}; $line <= $pattern->{eline}; $line += 1) {
$keywords->{$line - $example->{sline}} = $pattern->{id};
$map->{$line - $example->{sline}} = $pattern->{id};
}
}
}

return {package => $package, keywords => $keywords, sline => $sline, text => $text};
return {package => $package, matches => $matches, keywords => $keywords, sline => $sline, text => $text};
}

1;
Loading

0 comments on commit a965dab

Please sign in to comment.