def import_github(request): name = request.POST['name'] repo = request.POST['repo'] branch = request.POST['branch'] add_remote = (request.POST['add_remote'] == 'true') match = re.match( r'^(?:https?://|git@|git://)?(?:www\.)?github\.com[/:]([\w.-]+)/([\w.-]+?)(?:\.git|/|$)', repo) if match is None: raise BadRequest(_("Invalid Github URL.")) github_user = match.group(1) github_project = match.group(2) try: project = Project.objects.create(owner=request.user, name=name) except IntegrityError as e: raise BadRequest(str(e)) if add_remote: project.github_repo = "%s/%s" % (github_user, github_project) project.github_branch = branch project.save() task = do_import_github.delay(project.id, github_user, github_project, branch, delete_project=True) return {'task_id': task.task_id, 'project_id': project.id}
def rename_source_file(request, project_id, file_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) source_file = get_object_or_404(SourceFile, pk=file_id, project=project) old_filename = source_file.file_name if source_file.file_name != request.POST['old_name']: send_td_event('cloudpebble_rename_abort_unsafe', data={ 'data': { 'filename': source_file.file_name, 'kind': 'source' } }, request=request, project=project) raise BadRequest(_("Could not rename, file has been renamed already.")) if source_file.was_modified_since(int(request.POST['modified'])): send_td_event('cloudpebble_rename_abort_unsafe', data={ 'data': { 'filename': source_file.file_name, 'kind': 'source', 'modified': time.mktime(source_file.last_modified.utctimetuple()), } }, request=request, project=project) raise BadRequest(_("Could not rename, file has been modified since last save.")) source_file.file_name = request.POST['new_name'] source_file.save() send_td_event('cloudpebble_rename_file', data={ 'data': { 'old_filename': old_filename, 'new_filename': source_file.file_name, 'kind': 'source' } }, request=request, project=project) return {"modified": time.mktime(source_file.last_modified.utctimetuple())}
def delete_variant(request, project_id, resource_id, variant): project = get_object_or_404(Project, pk=project_id, owner=request.user) resource = get_object_or_404(ResourceFile, pk=resource_id, project=project) if variant == '0': variant = '' variant_to_delete = resource.variants.get(tags=variant) if resource.variants.count() == 1: raise BadRequest( _("You cannot delete the last remaining variant of a resource.")) variant_to_delete.delete() send_td_event('cloudpebble_delete_variant', data={ 'data': { 'filename': resource.file_name, 'kind': 'resource', 'resource-kind': resource.kind, 'variant': variant } }, request=request, project=project) return { 'resource': { 'variants': [x.get_tags() for x in resource.variants.all()] } }
def create_source_file(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) try: f = SourceFile.objects.create(project=project, file_name=request.POST['name'], target=request.POST.get('target', 'app')) f.save_text(request.POST.get('content', '')) except IntegrityError as e: raise BadRequest(str(e)) send_td_event('cloudpebble_create_file', data={ 'data': { 'filename': request.POST['name'], 'kind': 'source', 'target': f.target } }, request=request, project=project) return { 'file': { 'id': f.id, 'name': f.file_name, 'target': f.target, 'file_path': f.project_path } }
def delete_project(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) if not bool(request.POST.get('confirm', False)): raise BadRequest(_("Not confirmed")) project.delete() send_td_event('cloudpebble_delete_project', request=request, project=project)
def create_project(request): name = request.POST['name'] template_id = request.POST.get('template', None) if template_id is not None: template_id = int(template_id) project_type = request.POST.get('type', 'native') template_name = None sdk_version = str(request.POST.get('sdk', '2')) try: with transaction.atomic(): app_keys = '{}' if sdk_version == '2' else '[]' project = Project.objects.create( name=name, owner=request.user, app_company_name=request.user.username, app_short_name=name, app_long_name=name, app_version_label='1.0', app_is_watchface=False, app_capabilities='', project_type=project_type, sdk_version=sdk_version, app_keys=app_keys) if template_id is not None and template_id != 0: template = TemplateProject.objects.get(pk=template_id) template_name = template.name template.copy_into_project(project) elif project_type == 'simplyjs': f = SourceFile.objects.create(project=project, file_name="app.js") f.save_text( open('{}/src/html/demo.js'.format( settings.SIMPLYJS_ROOT)).read()) elif project_type == 'pebblejs': f = SourceFile.objects.create(project=project, file_name="app.js") f.save_text( open('{}/src/js/app.js'.format( settings.PEBBLEJS_ROOT)).read()) # TODO: Default file for Rocky? project.full_clean() project.save() except IntegrityError as e: raise BadRequest(str(e)) else: send_td_event( 'cloudpebble_create_project', {'data': { 'template': { 'id': template_id, 'name': template_name } }}, request=request, project=project) return {"id": project.id}
def import_zip(request): zip_file = request.FILES['archive'] name = request.POST['name'] try: project = Project.objects.create(owner=request.user, name=name) except IntegrityError as e: raise BadRequest(str(e)) task = do_import_archive.delay(project.id, zip_file.read(), delete_project=True) return {'task_id': task.task_id, 'project_id': project.id}
def save_project_dependencies(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) try: project.set_dependencies(json.loads(request.POST['dependencies'])) project.set_interdependencies([int(x) for x in json.loads(request.POST['interdependencies'])]) return {'dependencies': project.get_dependencies()} except (IntegrityError, ValueError) as e: raise BadRequest(str(e)) else: send_td_event('cloudpebble_save_project_settings', request=request, project=project)
def create_resource(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) kind = request.POST['kind'] resource_ids = json.loads(request.POST['resource_ids']) posted_file = request.FILES.get('file', None) file_name = request.POST['file_name'] new_tags = json.loads(request.POST['new_tags']) resources = [] try: with transaction.atomic(): rf = ResourceFile.objects.create(project=project, file_name=file_name, kind=kind) for r in resource_ids: resource_options = decode_resource_id_options(r) resources.append( ResourceIdentifier.objects.create(resource_file=rf, **resource_options)) if posted_file is not None: variant = ResourceVariant.objects.create( resource_file=rf, tags=",".join(str(int(t)) for t in new_tags)) variant.save_file(posted_file, posted_file.size) rf.save() except IntegrityError as e: raise BadRequest(e) send_td_event('cloudpebble_create_file', data={ 'data': { 'filename': file_name, 'kind': 'resource', 'resource-kind': kind } }, request=request, project=project) return { "file": { "id": rf.id, "kind": rf.kind, "file_name": rf.file_name, "resource_ids": [x.get_options_dict(with_id=True) for x in resources], "identifiers": [x.resource_id for x in resources], "variants": [x.get_tags() for x in rf.variants.all()], "extra": { y.resource_id: y.get_options_dict(with_id=False) for y in rf.identifiers.all() } } }
def save_published_media(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) try: project.set_published_media(json.loads( request.POST['published_media'])) except (IntegrityError, ValueError) as e: raise BadRequest(str(e)) else: send_td_event('cloudpebble_save_published_media', request=request, project=project) return {'published_media': project.get_published_media()}
def list_phones(request): user_key = request.user.social_auth.get(provider='pebble').extra_data['access_token'] response = requests.get( '{0}/api/v1/me'.format(settings.SOCIAL_AUTH_PEBBLE_ROOT_URL), headers={'Authorization': 'Bearer {0}'.format(user_key)}, params={'client_id': settings.SOCIAL_AUTH_PEBBLE_KEY}) if response.status_code != 200: if 400 <= response.status_code < 500: raise BadRequest(response.reason) else: raise Exception(response.reason) else: devices = response.json()['devices'] return {'devices': devices}
def save_project_settings(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) try: with transaction.atomic(): project.name = request.POST['name'] project.app_uuid = request.POST['app_uuid'] project.app_company_name = request.POST['app_company_name'] project.app_short_name = request.POST['app_short_name'] project.app_long_name = request.POST['app_long_name'] project.app_version_label = request.POST['app_version_label'] project.app_is_watchface = bool( int(request.POST['app_is_watchface'])) project.app_is_hidden = bool(int(request.POST['app_is_hidden'])) project.app_is_shown_on_communication = bool( int(request.POST['app_is_shown_on_communication'])) project.app_capabilities = request.POST['app_capabilities'] project.app_keys = request.POST['app_keys'] project.app_jshint = bool(int(request.POST['app_jshint'])) project.sdk_version = request.POST['sdk_version'] project.app_platforms = request.POST['app_platforms'] project.app_modern_multi_js = bool( int(request.POST['app_modern_multi_js'])) menu_icon = request.POST['menu_icon'] old_icon = project.menu_icon if menu_icon != '': menu_icon = int(menu_icon) if old_icon is not None: old_icon.is_menu_icon = False old_icon.save() icon_resource = project.resources.filter(id=menu_icon)[0] icon_resource.is_menu_icon = True icon_resource.save() elif old_icon is not None: old_icon.is_menu_icon = False old_icon.save() project.save() except IntegrityError as e: return BadRequest(str(e)) else: send_td_event('cloudpebble_save_project_settings', request=request, project=project)
def set_project_repo(request, project_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) repo = request.POST['repo'] branch = request.POST['branch'] auto_pull = bool(int(request.POST['auto_pull'])) auto_build = bool(int(request.POST['auto_build'])) repo = ide.git.url_to_repo(repo) if repo is None: raise BadRequest(_("Invalid repo URL.")) repo = '%s/%s' % repo g = ide.git.get_github(request.user) try: g_repo = g.get_repo(repo) except UnknownObjectException: return {'exists': False, 'access': False, 'updated': False, 'branch_exists': False} # TODO: Validate the branch...give user option to create one? with transaction.atomic(): if repo != project.github_repo: if project.github_hook_uuid: try: remove_hooks(g.get_repo(project.github_repo), project.github_hook_uuid) except: pass # Just clear the repo if none specified. if repo == '': project.github_repo = None project.github_branch = None project.github_last_sync = None project.github_last_commit = None project.github_hook_uuid = None project.save() return {'exists': True, 'access': True, 'updated': True, 'branch_exists': True} if not ide.git.git_verify_tokens(request.user): raise BadRequest(_("No GitHub tokens on file.")) try: has_access = ide.git.check_repo_access(request.user, repo) except UnknownObjectException: return {'exists': False, 'access': False, 'updated': False, 'branch_exists': False} if has_access: project.github_repo = repo project.github_branch = branch project.github_last_sync = None project.github_last_commit = None project.github_hook_uuid = None else: return {'exists': True, 'access': True, 'updated': True, 'branch_exists': True} if branch != project.github_branch: project.github_branch = branch if auto_pull and project.github_hook_uuid is None: # Generate a new hook UUID project.github_hook_uuid = uuid.uuid4().hex # Set it up g_repo.create_hook('web', {'url': settings.GITHUB_HOOK_TEMPLATE % {'project': project.id, 'key': project.github_hook_uuid}, 'content_type': 'form'}, ['push'], True) elif not auto_pull: if project.github_hook_uuid is not None: try: remove_hooks(g_repo, project.github_hook_uuid) except: pass project.github_hook_uuid = None project.github_hook_build = auto_build project.save() send_td_event('cloudpebble_project_github_linked', data={ 'data': { 'repo': project.github_repo, 'branch': project.github_branch } }, request=request, project=project) return {'exists': True, 'access': True, 'updated': True, 'branch_exists': True}
def update_resource(request, project_id, resource_id): project = get_object_or_404(Project, pk=project_id, owner=request.user) resource = get_object_or_404(ResourceFile, pk=resource_id, project=project) resource_ids = json.loads(request.POST['resource_ids']) file_name = request.POST.get('file_name', None) variant_tags = json.loads(request.POST.get('variants', "[]")) new_tags = json.loads(request.POST.get('new_tags', "[]")) replacement_map = json.loads(request.POST.get('replacements', "[]")) replacement_files = request.FILES.getlist('replacement_files[]') try: with transaction.atomic(): # Lazy approach: delete all the resource_ids and recreate them. # We could do better. resources = [] ResourceIdentifier.objects.filter(resource_file=resource).delete() for r in resource_ids: resource_options = decode_resource_id_options(r) resources.append( ResourceIdentifier.objects.create(resource_file=resource, **resource_options)) # We get sent a list of (tags_before, tags_after) pairs. updated_variants = [] for tag_update in variant_tags: tags_before, tags_after = tag_update variant = resource.variants.get(tags=tags_before) variant.set_tags(tags_after) updated_variants.append(variant) for variant in updated_variants: variant.save() if 'file' in request.FILES: variant = resource.variants.create(tags=",".join( str(int(t)) for t in new_tags)) variant.save_file(request.FILES['file'], request.FILES['file'].size) # We may get sent a list of pairs telling us which variant gets which replacement file for tags, file_index in replacement_map: variant = resource.variants.get(tags=tags) replacement = replacement_files[int(file_index)] variant.save_file(replacement, replacement.size) if file_name and resource.file_name != file_name: resource.file_name = file_name resource.save() except IntegrityError as e: raise BadRequest(str(e)) send_td_event( 'cloudpebble_save_file', data={'data': { 'filename': resource.file_name, 'kind': 'source' }}, request=request, project=project) return { "file": { "id": resource.id, "kind": resource.kind, "file_name": resource.file_name, "resource_ids": [x.get_options_dict(with_id=True) for x in resources], "identifiers": [x.resource_id for x in resources], "variants": [x.get_tags() for x in resource.variants.all()], "extra": { y.resource_id: y.get_options_dict(with_id=False) for y in resource.identifiers.all() } } }