Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private repo #3728

Merged
merged 47 commits into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
43cab9d
mackup
octavioamu Feb 11, 2019
f8bf7a6
Merge branch 'master' into private-repo
octavioamu Feb 12, 2019
2a42ed0
mackup
octavioamu Feb 11, 2019
6a653ee
change visual fund new
octavioamu Feb 14, 2019
0a28d58
Backend for private repo
SaptakS Feb 13, 2019
faeda64
Merge branch 'master' into private-repo
SaptakS Feb 14, 2019
27ed280
add fields
octavioamu Feb 15, 2019
b318a3d
Merge branch 'private-repo' of https://github.com/gitcoinco/web into …
octavioamu Feb 15, 2019
29af38f
fix lint
octavioamu Feb 15, 2019
d9b97c4
Adds validation for private repo checks in backend
SaptakS Feb 15, 2019
4b2df80
Adds private repo validation in js on frontend submission of form
SaptakS Feb 15, 2019
a512329
commented out v2
octavioamu Feb 15, 2019
72638e1
add nda, change modal
octavioamu Feb 15, 2019
233edfd
change validation
octavioamu Feb 15, 2019
75a2ea4
Adds backend for unsigned nda
SaptakS Feb 18, 2019
0dc7df6
Merge branch 'private-repo' of github.com:gitcoinco/web into private-…
SaptakS Feb 18, 2019
58d387b
Adds uploading of signed and unsigned nda
SaptakS Feb 19, 2019
593c0cb
Fixes isort
SaptakS Feb 19, 2019
cd4d15d
Fixes foreign key assignment and fetching in DRF
SaptakS Feb 20, 2019
f986344
add nda download
octavioamu Feb 21, 2019
5960905
change button when private repo
octavioamu Feb 21, 2019
4a90676
fix send interest
octavioamu Feb 21, 2019
b28a4f3
clean code
octavioamu Feb 21, 2019
9d72797
add doc in activity
octavioamu Feb 21, 2019
0d85a44
Merge branch 'master' into private-repo
octavioamu Feb 21, 2019
5e4099a
Merge branch 'master' into private-repo
octavioamu Feb 22, 2019
878e898
add private modal
octavioamu Feb 26, 2019
9ce2fd8
add condition to private instructions
octavioamu Feb 26, 2019
2ac7dd1
Merge branch 'master' into private-repo
octavioamu Feb 28, 2019
ec48e03
Merge branch 'master' into private-repo
octavioamu Feb 28, 2019
f54a762
add email for private repo
octavioamu Feb 28, 2019
a5c9fec
Merge branch 'master' into private-repo
octavioamu Feb 28, 2019
b0aba5c
Fix migration conflicts
SaptakS Feb 28, 2019
c233280
Merge branch 'master' into private-repo
SaptakS Mar 7, 2019
9eaca2c
Merge branch 'master' into private-repo
octavioamu Mar 11, 2019
4fe2b2f
solve migrations conflict
octavioamu Mar 11, 2019
6a924ce
Merge branch 'private-repo' of https://github.com/gitcoinco/web into …
octavioamu Mar 11, 2019
86942a6
fix isort
octavioamu Mar 11, 2019
e564b84
Merge branch 'master' into private-repo
octavioamu Mar 13, 2019
26d6b23
remove dead code
octavioamu Mar 14, 2019
6467e01
Merge branch 'master' into private-repo
octavioamu Mar 19, 2019
831fbfa
fix migrations
octavioamu Mar 19, 2019
db79e7d
fix isort
octavioamu Mar 19, 2019
b9743b1
Merge branch 'master' into private-repo
octavioamu Mar 21, 2019
0f10872
Fixes migrations related_names
SaptakS Mar 25, 2019
1d5ec38
Merge branch 'master' into private-repo
SaptakS Mar 26, 2019
cdf21ac
Merge branch 'master' into private-repo
octavioamu Mar 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@
dashboard.views.profile_job_opportunity,
name='profile_job_opportunity'
),
url(
r'^api/v0.1/bountydocument',
dashboard.views.bounty_upload_nda,
name='bounty_upload_nda'
),
url(r'^api/v0.1/faucet/save/?', faucet.views.save_faucet, name='save_faucet'),
url(r'^api/v0.1/', include(dbrouter.urls)),
url(r'^api/v0.1/', include(kdrouter.urls)),
Expand Down
11 changes: 10 additions & 1 deletion app/app/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import email
import imaplib
import logging
import os
import re
import time
from hashlib import sha1
from secrets import token_hex

from django.conf import settings
from django.contrib.auth.models import User
Expand All @@ -17,7 +19,6 @@
import requests
from avatar.models import SocialAvatar
from avatar.utils import get_svg_templates, get_user_github_avatar_image
from dashboard.models import Profile
from geoip2.errors import AddressNotFoundError
from git.utils import _AUTH, HEADERS, get_user
from ipware.ip import get_real_ip
Expand Down Expand Up @@ -161,6 +162,7 @@ def setup_lang(request, user):
DoesNotExist: The exception is raised if no profile is found for the specified handle.

"""
from dashboard.models import Profile
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you move this import within the function from the top of the file?

Copy link
Contributor

@SaptakS SaptakS Mar 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aah. This is to avoid recursive import here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much time do you think it would take to refactor out the recursive import? Imports within a function aren't terribly bad, but I think for webservers they can really affect performance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will take a lot of adjustments in a lot of places. If it's not too much bad for the performance, I think we can do it in a later adjustment.

profile = None
if user.is_authenticated and hasattr(user, 'profile'):
profile = user.profile
Expand All @@ -174,7 +176,14 @@ def setup_lang(request, user):
request.session.modified = True


def get_upload_filename(instance, filename):
salt = token_hex(16)
file_path = os.path.basename(filename)
return f"docs/{getattr(instance, '_path', '')}/{salt}/{file_path}"


def sync_profile(handle, user=None, hide_profile=True):
from dashboard.models import Profile
handle = handle.strip().replace('@', '').lower()
data = get_user(handle)
email = ''
Expand Down
24 changes: 24 additions & 0 deletions app/assets/v2/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -1654,3 +1654,27 @@ div.busyOverlay {
border: 0.25em solid currentColor;
border-radius: 100px;
}

.cta-blue {
background: #0D0764;
color: white;
padding: 1.8rem;
border-radius: 0.2rem;
}

.privaterepo-instructions {
background: #F8F8F8;
padding: 1rem;
}

@media (min-width: 768px) {
.privaterepo-instructions {
width: 75%;
}

}

.g-modal .modal-header,
.g-modal .modal-footer {
border: none;
}
9 changes: 8 additions & 1 deletion app/assets/v2/css/forms/checkbox.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
background: #fff;
border: 1px solid #dbdbdb;
border-radius: 2px;
content: url('/static/v2/images/check.svg');
content: '';
display: inline-flex;
justify-content: center;
height: 18px;
Expand All @@ -30,11 +30,18 @@
color: #D50000;
}

.form__checkbox input:disabled ~ .form__label::before {
background-color: #d0d0d0 !important;
border-color: #d0d0d0 !important;
cursor: not-allowed;
}

.form__checkbox label.error {
display: none !important;
}

.form__checkbox input:checked ~ .form__label::before {
background-color: #0D0764;
border-color: #0D0764;
content: url('/static/v2/images/check.svg');
}
4 changes: 2 additions & 2 deletions app/assets/v2/css/forms/select.css
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

.form__select2 .select2-container {
display: inline-block !important;
width: 100% !important;
min-width: 100%;
height: 100%;
font-size: 14px;
}
Expand Down Expand Up @@ -161,4 +161,4 @@

.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #ffffff;
}
}
Binary file added app/assets/v2/images/emails/private-repo-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/emails/private-repo-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/emails/private-repo-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/emails/private-repo-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/repo-instructions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/repo-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
537 changes: 537 additions & 0 deletions app/assets/v2/images/robots-party.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions app/assets/v2/js/ajax-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
* Generic function to make an AJAX call avoid DRY
*
* ex:
* var getdata = fetchData ('/api/v0.1/data/','GET')
* $.when( getdata ).then( function ( response ){ return response })
* var getdata = fetchData('/api/v0.1/data/','GET')
* $.when(getdata).then(function(response){ return response })
*
* var sendForm = fetchData ( e.currentTarget.action,
* var sendForm = fetchData(e.currentTarget.action,
* e.currentTarget.method,
* $("#form-wallets").serialize()
* )
* $.when( sendForm ).then( function ( payback ){ return payback })
* $.when(sendForm).then(function(payback){ return payback })
*
*/

Expand Down
149 changes: 121 additions & 28 deletions app/assets/v2/js/pages/bounty_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,51 +633,132 @@ var attach_override_status = function() {
});
};


var show_interest_modal = function() {
var self = this;
let modals = $('#modalInterest');
let modalBody = $('#modalInterest .modal-content');
let modalUrl = `/interest/modal?redirect=${window.location.pathname}&pk=${document.result['pk']}`;

modals.on('show.bs.modal', function() {
modalBody.load(modalUrl, ()=> {
if (document.result['repo_type'] === 'private') {
$('#nda-upload').show();
$('#issueNDA').prop('required', true);
document.result.unsigned_nda ? $('.nda-download-link').attr('href', document.result.unsigned_nda.doc) : $('#nda-upload').hide();
}

setTimeout(function() {
var url = '/interest/modal?redirect=' + window.location.pathname + '&pk=' + document.result['pk'];

$.get(url, function(newHTML) {
var modal = $(newHTML).appendTo('body').modal({
modalClass: 'modal add-interest-modal'
});

var actionPlanForm = modal.find('form#action_plan');
var issueMessage = actionPlanForm.find('#issue_message');
let actionPlanForm = $('#action_plan');
let issueMessage = $('#issue_message');

issueMessage.attr('placeholder', gettext('What steps will you take to complete this task? (min 30 chars)'));

modal.on('submit', function(event) {
actionPlanForm.on('submit', function(event) {
event.preventDefault();

var msg = issueMessage.val().trim();
let msg = issueMessage.val().trim();
let issueNDA = $('#issueNDA')[0].files;

if (!msg || msg.length < 30) {
_alert({message: gettext('Please provide an action plan for this ticket. (min 30 chars)')}, 'error');
return false;
}

if (typeof issueNDA[0] !== 'undefined') {
const formData = new FormData();

formData.append('docs', issueNDA[0]);
formData.append('doc_type', 'signed_nda');
const ndaSend = {
url: '/api/v0.1/bountydocument',
method: 'POST',
data: formData,
processData: false,
dataType: 'json',
contentType: false
};

$.ajax(ndaSend).done(function(response) {
_alert(response.message, 'info');
add_interest(document.result['pk'], {
issue_message: msg,
signed_nda: response.bounty_doc_id
}).then(success => {
if (success) {
$(self).attr('href', '/uninterested');
$(self).find('span').text(gettext('Stop Work'));
$(self).parent().attr('title', '<div class="tooltip-info tooltip-sm">' + gettext('Notify the funder that you will not be working on this project') + '</div>');
$.modal.close();
}
}).catch((error) => {
if (error.responseJSON.error === 'You may only work on max of 3 issues at once.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way we can check for this error? I worry that in the future we may change this error message and not realize that it will break this.

return;
throw error;
});
}).fail(function(error) {
_alert(error, 'error');
});
} else {
add_interest(document.result['pk'], {
issue_message: msg
}).then(success => {
if (success) {
$(self).attr('href', '/uninterested');
$(self).find('span').text(gettext('Stop Work'));
$(self).parent().attr('title', '<div class="tooltip-info tooltip-sm">' + gettext('Notify the funder that you will not be working on this project') + '</div>');
$.modal.close();
}
}).catch((error) => {
if (error.responseJSON.error === 'You may only work on max of 3 issues at once.')
return;
throw error;
});
}

add_interest(document.result['pk'], {
issue_message: msg
}).then(success => {
if (success) {
$(self).attr('href', '/uninterested');
$(self).find('span').text(gettext('Stop Work'));
$(self).parent().attr('title', '<div class="tooltip-info tooltip-sm">' + gettext('Notify the funder that you will not be working on this project') + '</div>');
$.modal.close();
}
}).catch((error) => {
if (error.responseJSON.error === 'You may only work on max of 3 issues at once.')
return;
throw error;
});
});

});
});
modals.bootstrapModal('show');
};

const repoInstructions = () => {
let linkToSettings = `https://github.com/${document.result.github_org_name}/${document.result.github_repo_name}/settings/collaboration`;


let modalTmp = `
<div class="modal fade g-modal" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-center center-block w-75">
<h5>
You have successfully approved the contributor to work on your bounty!
</h5>
<div>
<img src="${document.contxt.STATIC_URL}v2/images/repo-instructions.png" class="mw-100 my-4" alt="">
</div>
<p class="mb-4">Now you need to invite the contributor to your private repo on GitHub You can find it under <b>GitHub repository > Settings > Collaborators</b></p>
<div>
<img src="${document.contxt.STATIC_URL}v2/images/repo-settings.png" class="mw-100" alt="">
</div>
</div>
<div class="modal-footer justify-content-center">
<a href="${linkToSettings}" target="_blank" class="button button--primary"><i class="fab fa-github"></i> Go to Repo Settings</a>
</div>
</div>
</div>
</div>`;

$(modalTmp).bootstrapModal('show');

$(document, modalTmp).on('hidden.bs.modal', function(e) {
$('#exampleModalCenter').remove();
$(modalTmp).bootstrapModal('dispose');
});
};

var set_extended_time_html = function(extendedDuration, currentExpires) {
Expand Down Expand Up @@ -1055,7 +1136,8 @@ var do_actions = function(result) {
const _entry = {
enabled: true,
href: github_url,
text: gettext('View On Github') +
text: (result['repo_type'] === 'private' ? '<i class="fas fa-lock"></i> ' +
gettext('Private Repo') : gettext('View On Github')) +
(result['is_issue_closed'] ? gettext(' (Issue is closed)') : ''),
parent: 'right_actions',
title: gettext('View issue details and comments on Github'),
Expand Down Expand Up @@ -1266,6 +1348,10 @@ var pull_bounty_from_api = function() {
render_activity(result, results);

document.result = result;

if (typeof promptPrivateInstructions !== 'undefined' && result.repo_type === 'private') {
repoInstructions();
}
return;
}
}
Expand Down Expand Up @@ -1324,6 +1410,12 @@ const process_activities = function(result, bounty_activities) {
const fulfillment = meta.fulfillment || {};
const new_bounty = meta.new_bounty || {};
const old_bounty = meta.old_bounty || {};
const has_signed_nda = result.interested.map(interest => {
if (interest.profile.handle === _activity.profile.handle && interest.signed_nda) {
return interest.signed_nda.doc;
}
return false;
});
const has_pending_interest = !!result.interested.find(interest =>
interest.profile.handle === _activity.profile.handle && interest.pending);
const has_interest = !!result.interested.find(interest =>
Expand Down Expand Up @@ -1357,6 +1449,7 @@ const process_activities = function(result, bounty_activities) {
age: timeDifference(now, new Date(_activity.created)),
activity_type: _activity.activity_type,
status: _activity.activity_type === 'work_started' ? 'started' : 'stopped',
signed_nda: has_signed_nda,
uninterest_possible: uninterest_possible,
slash_possible: slash_possible,
approve_worker_url: meta.approve_worker_url,
Expand Down
Loading