mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
Merge remote-tracking branch 'origin/projects-to-markdown' into projects-improvements
This commit is contained in:
commit
b8fd8d8172
4
Gemfile
4
Gemfile
@ -30,6 +30,7 @@ group :development, :test do
|
|||||||
# comment over to use visual debugger (eg. RubyMine), uncomment to use manual debugging
|
# comment over to use visual debugger (eg. RubyMine), uncomment to use manual debugging
|
||||||
# gem 'byebug'
|
# gem 'byebug'
|
||||||
gem 'dotenv-rails'
|
gem 'dotenv-rails'
|
||||||
|
gem 'pry'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
@ -43,7 +44,6 @@ group :development do
|
|||||||
# Preview mail in the browser
|
# Preview mail in the browser
|
||||||
gem 'listen', '~> 3.0.5'
|
gem 'listen', '~> 3.0.5'
|
||||||
gem 'overcommit'
|
gem 'overcommit'
|
||||||
gem 'pry'
|
|
||||||
gem 'rb-readline'
|
gem 'rb-readline'
|
||||||
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
||||||
gem 'railroady'
|
gem 'railroady'
|
||||||
@ -149,3 +149,5 @@ gem 'acts_as_list'
|
|||||||
# Error reporting
|
# Error reporting
|
||||||
gem 'sentry-rails'
|
gem 'sentry-rails'
|
||||||
gem 'sentry-ruby'
|
gem 'sentry-ruby'
|
||||||
|
|
||||||
|
gem "reverse_markdown"
|
||||||
|
@ -398,6 +398,8 @@ GEM
|
|||||||
responders (3.1.0)
|
responders (3.1.0)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
|
reverse_markdown (2.1.1)
|
||||||
|
nokogiri
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rolify (5.3.0)
|
rolify (5.3.0)
|
||||||
rubocop (1.31.2)
|
rubocop (1.31.2)
|
||||||
@ -590,6 +592,7 @@ DEPENDENCIES
|
|||||||
redis-session-store
|
redis-session-store
|
||||||
repost
|
repost
|
||||||
responders (~> 3.0)
|
responders (~> 3.0)
|
||||||
|
reverse_markdown
|
||||||
rolify
|
rolify
|
||||||
rubocop (~> 1.31)
|
rubocop (~> 1.31)
|
||||||
rubocop-rails
|
rubocop-rails
|
||||||
|
@ -18,6 +18,12 @@ class API::ProjectsController < API::APIController
|
|||||||
@project = Project.friendly.find(params[:id])
|
@project = Project.friendly.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def markdown
|
||||||
|
@project = Project.friendly.find(params[:id])
|
||||||
|
authorize @project
|
||||||
|
send_data ProjectToMarkdown.new(@project).call, filename: "#{@project.name.parameterize}-#{@project.id}.md", disposition: 'attachment', type: 'text/markdown'
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@project = Project.new(project_params.merge(author_statistic_profile_id: current_user.statistic_profile.id))
|
@project = Project.new(project_params.merge(author_statistic_profile_id: current_user.statistic_profile.id))
|
||||||
if @project.save
|
if @project.save
|
||||||
@ -53,12 +59,23 @@ class API::ProjectsController < API::APIController
|
|||||||
|
|
||||||
def search
|
def search
|
||||||
service = ProjectService.new
|
service = ProjectService.new
|
||||||
res = service.search(params, current_user)
|
paginate = request.format.zip? ? false : true
|
||||||
|
res = service.search(params, current_user, paginate: paginate)
|
||||||
|
|
||||||
render json: res, status: :unprocessable_entity and return if res[:error]
|
render json: res, status: :unprocessable_entity and return if res[:error]
|
||||||
|
|
||||||
@total = res[:total]
|
respond_to do |format|
|
||||||
@projects = res[:projects]
|
format.json do
|
||||||
render :index
|
@total = res[:total]
|
||||||
|
@projects = res[:projects]
|
||||||
|
render :index
|
||||||
|
end
|
||||||
|
format.zip do
|
||||||
|
head :forbidden unless current_user.admin? || current_user.manager?
|
||||||
|
|
||||||
|
send_data ProjectsArchive.new(res[:projects]).call, filename: "projets.zip", disposition: 'attachment', type: 'application/zip'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -380,6 +380,8 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
|
|||||||
$scope.triggerSearch();
|
$scope.triggerSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.zipUrl = '/api/projects/search.zip';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback triggered when the button "search from the whole network" is toggled
|
* Callback triggered when the button "search from the whole network" is toggled
|
||||||
*/
|
*/
|
||||||
@ -481,6 +483,7 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
|
|||||||
const toDate = search.to_date ? search.to_date.toDateString() : undefined;
|
const toDate = search.to_date ? search.to_date.toDateString() : undefined;
|
||||||
updateUrlParam('to_date', toDate);
|
updateUrlParam('to_date', toDate);
|
||||||
updateUrlParam('project_category_id', search.project_category_id);
|
updateUrlParam('project_category_id', search.project_category_id);
|
||||||
|
$scope.zipUrl = '/api/projects/search.zip?' + new URLSearchParams({ search: JSON.stringify($location.search()) }).toString();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,6 +106,12 @@
|
|||||||
|
|
||||||
<status-filter on-filter-change="onStatusChange" current-status-index="search.status_id"/>
|
<status-filter on-filter-change="onStatusChange" current-status-index="search.status_id"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center m m-b-lg" ng-if="!openlab.searchOverWholeNetwork && (projects.length != 0) && (isAuthorized('admin') || isAuthorized('manager'))">
|
||||||
|
<a class="btn bg-light text-black" ng-href="{{ zipUrl }}" target="_blank">
|
||||||
|
<i class="fa fa-download"></i> {{ 'app.public.projects_list.download_archive' | translate }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="projects-list">
|
<div class="projects-list">
|
||||||
|
@ -1,199 +1,202 @@
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
<section class="heading b-b">
|
<section class="heading b-b">
|
||||||
|
<div class="row no-gutter">
|
||||||
|
<div class="col-xs-2 col-sm-2 col-md-1">
|
||||||
|
<section class="heading-btn">
|
||||||
|
<a ng-click="backPrevLocation($event)"><i class="fas fa-long-arrow-alt-left "></i></a>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
||||||
|
<section class="heading-title">
|
||||||
|
<h1>{{ project.name }} <span class="badge" ng-if="project.state == 'draft'" translate>{{ 'app.public.projects_show.rough_draft' }}</span></h1>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||||
|
<section class="heading-actions wrapper">
|
||||||
|
|
||||||
|
<a ui-sref="app.logged.projects_edit({id: project.id})" ng-if="projectEditableBy(currentUser) || isAuthorized('admin')" class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs text-u-c text-sm"><i class="fa fa-edit"></i> {{ 'app.shared.buttons.edit' | translate }}</a>
|
||||||
|
<a ng-click="deleteProject(event)" ng-if="projectDeletableBy(currentUser) || isAuthorized('admin')" class="btn btn-lg btn-danger b-2x rounded no-b m-t-xs"><i class="fa fa-trash-o"></i></a>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter">
|
<div class="row no-gutter">
|
||||||
<div class="col-xs-2 col-sm-2 col-md-1">
|
<div class="col-sm-12 col-md-12 col-lg-9 b-r-lg">
|
||||||
<section class="heading-btn">
|
|
||||||
<a ng-click="backPrevLocation($event)"><i class="fas fa-long-arrow-alt-left "></i></a>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
|
||||||
<section class="heading-title">
|
|
||||||
<h1>{{ project.name }} <span class="badge" ng-if="project.state == 'draft'" translate>{{ 'app.public.projects_show.rough_draft' }}</span></h1>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
|
||||||
<section class="heading-actions wrapper">
|
|
||||||
|
|
||||||
<a ui-sref="app.logged.projects_edit({id: project.id})" ng-if="projectEditableBy(currentUser) || isAuthorized('admin')" class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs text-u-c text-sm"><i class="fa fa-edit"></i> {{ 'app.shared.buttons.edit' | translate }}</a>
|
|
||||||
<a ng-click="deleteProject(event)" ng-if="projectDeletableBy(currentUser) || isAuthorized('admin')" class="btn btn-lg btn-danger b-2x rounded no-b m-t-xs"><i class="fa fa-trash-o"></i></a>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row no-gutter">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-9 b-r-lg">
|
|
||||||
|
|
||||||
<div class="article wrapper-lg">
|
|
||||||
|
|
||||||
<div class="article-thumbnail" ng-if="project.project_image">
|
|
||||||
<a href="{{project.project_full_image}}" target="_blank"><img ng-src="{{project.project_image}}" alt="{{project.name}}"></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 translate>{{ 'app.public.projects_show.project_description' }}</h3>
|
|
||||||
<p ng-bind-html="project.description | toTrusted"></p>
|
|
||||||
|
|
||||||
<div class="article-steps">
|
|
||||||
<div class="row article-step m-b-lg" ng-repeat="step in project.project_steps_attributes">
|
|
||||||
<div class="col-md-12 m-b-xs">
|
|
||||||
<h3 class="well well-simple step-title">{{ 'app.public.projects_show.step_N' | translate:{INDEX:step.step_nb} }} : {{step.title}}</h3>
|
|
||||||
</div>
|
|
||||||
<div ng-repeat-start="image in step.project_step_images_attributes" class="clearfix" ng-if="$index % 3 == 0"></div>
|
|
||||||
<div class="col-md-4" ng-repeat-end>
|
|
||||||
<a href="{{image.attachment_full_url}}" target="_blank"><img class="m-b" ng-src="{{image.attachment_url}}" alt="{{image.attachment}}" ></a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8" ng-class="{'col-md-12' : step.project_step_images_attributes.length > 1 || step.project_step_images_attributes.length == 0}">
|
|
||||||
|
|
||||||
<p ng-bind-html="step.description | toTrusted"></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="article wrapper-lg">
|
||||||
|
|
||||||
|
<div class="article-thumbnail" ng-if="project.project_image">
|
||||||
|
<a href="{{project.project_full_image}}" target="_blank"><img ng-src="{{project.project_image}}" alt="{{project.name}}"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3 translate>{{ 'app.public.projects_show.project_description' }}</h3>
|
||||||
|
<p ng-bind-html="project.description | toTrusted"></p>
|
||||||
|
|
||||||
|
<div class="article-steps">
|
||||||
|
<div class="row article-step m-b-lg" ng-repeat="step in project.project_steps_attributes">
|
||||||
|
<div class="col-md-12 m-b-xs">
|
||||||
|
<h3 class="well well-simple step-title">{{ 'app.public.projects_show.step_N' | translate:{INDEX:step.step_nb} }} : {{step.title}}</h3>
|
||||||
|
</div>
|
||||||
|
<div ng-repeat-start="image in step.project_step_images_attributes" class="clearfix" ng-if="$index % 3 == 0"></div>
|
||||||
|
<div class="col-md-4" ng-repeat-end>
|
||||||
|
<a href="{{image.attachment_full_url}}" target="_blank"><img class="m-b" ng-src="{{image.attachment_url}}" alt="{{image.attachment}}" ></a>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8" ng-class="{'col-md-12' : step.project_step_images_attributes.length > 1 || step.project_step_images_attributes.length == 0}">
|
||||||
|
|
||||||
|
<p ng-bind-html="step.description | toTrusted"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center" id="social-share">
|
||||||
|
<a ng-href="{{shareOnFacebook()}}" target="_blank" class="btn btn-facebook btn-lg m-t"><i class="fa fa-facebook m-r"></i> {{ 'app.public.projects_show.share_on_facebook' | translate }}</a>
|
||||||
|
<a ng-href="{{shareOnTwitter()}}" target="_blank" class="btn btn-twitter btn-lg m-t"><i class="fa fa-twitter m-r"></i> {{ 'app.public.projects_show.share_on_twitter' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper-lg" ng-if="disqusShortname">
|
||||||
|
<dir-disqus disqus-shortname="{{ disqusShortname }}" disqus-identifier="project_{{ project.id }}" disqus-url="{{ projectUrl }}" ready-to-bind="{{ project }}">
|
||||||
|
</dir-disqus>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center" id="social-share">
|
<div class="col-sm-12 col-md-12 col-lg-3">
|
||||||
<a ng-href="{{shareOnFacebook()}}" target="_blank" class="btn btn-facebook btn-lg m-t"><i class="fa fa-facebook m-r"></i> {{ 'app.public.projects_show.share_on_facebook' | translate }}</a>
|
|
||||||
<a ng-href="{{shareOnTwitter()}}" target="_blank" class="btn btn-twitter btn-lg m-t"><i class="fa fa-twitter m-r"></i> {{ 'app.public.projects_show.share_on_twitter' | translate }}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wrapper-lg" ng-if="disqusShortname">
|
|
||||||
<dir-disqus disqus-shortname="{{ disqusShortname }}" disqus-identifier="project_{{ project.id }}" disqus-url="{{ projectUrl }}" ready-to-bind="{{ project }}">
|
|
||||||
</dir-disqus>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-3">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="text-center m-t-lg m-v">
|
<div class="text-center m-t-lg m-v">
|
||||||
<div class="thumb-lg m-b-xs">
|
<div class="thumb-lg m-b-xs">
|
||||||
<fab-user-avatar ng-model="project.author.user_avatar" avatar-class="thumb-50"></fab-user-avatar>
|
<fab-user-avatar ng-model="project.author.user_avatar" avatar-class="thumb-50"></fab-user-avatar>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a ng-show="project.author_id" class="text-sm font-sbold project-author" ui-sref="app.logged.members_show({id: project.author.slug})">
|
||||||
|
<i> {{ 'app.public.projects_show.by_name' | translate:{NAME:project.author.first_name} }}</i>
|
||||||
|
</a>
|
||||||
|
<span ng-hide="project.author_id" class="text-sm font-sbold text-gray" translate>{{ 'app.public.projects_show.deleted_user' }}</span>
|
||||||
|
</div>
|
||||||
|
<small class="text-xs m-b"><i>{{ 'app.public.projects_show.posted_on_' | translate }} {{project.created_at | amDateFormat: 'LL'}}</i></small>
|
||||||
|
|
||||||
|
<div class="m" ng-if="project.themes">
|
||||||
|
<span ng-repeat="theme in project.themes" class="badge m-r-sm">
|
||||||
|
{{theme.name}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a ng-show="project.author_id" class="text-sm font-sbold project-author" ui-sref="app.logged.members_show({id: project.author.slug})">
|
|
||||||
<i> {{ 'app.public.projects_show.by_name' | translate:{NAME:project.author.first_name} }}</i>
|
<section class="widget panel b-a m" ng-if="project.project_caos_attributes">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<span class="badge bg-warning pull-right">{{project.project_caos_attributes.length}}</span>
|
||||||
|
<h3 translate translate-values="{COUNT:project.project_caos_attributes.length}">{{ 'app.public.projects_show.CAD_file_to_download' }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="widget-content list-group list-group-lg no-bg auto">
|
||||||
|
<li ng-repeat="file in project.project_caos_attributes" class="list-group-item no-b clearfix">
|
||||||
|
<a target="_blank" ng-href="{{file.attachment_url}}" download="{{file.attachment_url}}"><i class="fa fa-arrow-circle-o-down"> </i> {{file.attachment | humanize : 25}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.status">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<h3 translate>{{ 'app.public.projects_show.status' }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ project.status.name }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.machines">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<span class="badge bg-warning pull-right">{{project.machines.length}}</span>
|
||||||
|
<h3 translate>{{ 'app.public.projects_show.machines_and_materials' }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="widget-content list-group list-group-lg no-bg auto">
|
||||||
|
<li ng-repeat="machine in project.machines" class="list-group-item no-b clearfix">
|
||||||
|
<a ui-sref="app.public.machines_show({id: machine.id})">{{machine.name}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="widget-content list-group list-group-lg no-bg auto">
|
||||||
|
<li ng-repeat="component in project.components" class="list-group-item no-b clearfix">
|
||||||
|
{{component.name}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.project_users.length > 0">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<span class="badge bg-warning pull-right">{{project.project_users.length}}</span>
|
||||||
|
<h3 translate>{{ 'app.public.projects_show.collaborators' }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="widget-content list-group list-group-lg no-bg auto">
|
||||||
|
<li class="list-group-item no-b clearfix block-link" ng-repeat="collaborator in project.project_users" ui-sref="app.logged.members_show({id: collaborator.slug})">
|
||||||
|
<span class="pull-left thumb-sm avatar m-r">
|
||||||
|
<fab-user-avatar ng-model="collaborator.user_avatar" avatar-class="thumb-38"></fab-user-avatar>
|
||||||
|
|
||||||
|
<i class="on b-white bottom" ng-if="collaborator.is_valid"></i>
|
||||||
|
<i class="off b-white bottom" ng-if="!collaborator.is_valid"></i>
|
||||||
|
</span>
|
||||||
|
<span class="clear"><span>{{collaborator.full_name}}</span>
|
||||||
|
<small class="text-muted clear text-ellipsis text-c">{{collaborator.username}}</small>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.licence">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<h3 translate>{{ 'app.public.projects_show.licence' }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ project.licence.name }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.tags">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<h3 translate>{{ 'app.shared.project.tags' }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<pre>{{ project.tags }}</pre>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="widget panel b-a m" ng-if="project.project_categories">
|
||||||
|
<div class="panel-heading b-b">
|
||||||
|
<h3 translate>{{ projectCategoriesWording }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="widget-content list-group list-group-lg no-bg auto">
|
||||||
|
<li ng-repeat="projectCategory in project.project_categories" class="list-group-item no-b clearfix">
|
||||||
|
{{projectCategory.name}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="text-center m m-b-lg" ng-if="projectEditableBy(currentUser) || isAuthorized('admin') || isAuthorized('manager')">
|
||||||
|
<a class="btn bg-light text-black" ng-href="api/projects/{{ project.id}}/markdown" target="_blank">
|
||||||
|
<i class="fa fa-download"></i> {{ 'app.public.projects_show.markdown_file' | translate }}
|
||||||
</a>
|
</a>
|
||||||
<span ng-hide="project.author_id" class="text-sm font-sbold text-gray" translate>{{ 'app.public.projects_show.deleted_user' }}</span>
|
|
||||||
</div>
|
|
||||||
<small class="text-xs m-b"><i>{{ 'app.public.projects_show.posted_on_' | translate }} {{project.created_at | amDateFormat: 'LL'}}</i></small>
|
|
||||||
|
|
||||||
<div class="m" ng-if="project.themes">
|
|
||||||
<span ng-repeat="theme in project.themes" class="badge m-r-sm">
|
|
||||||
{{theme.name}}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<section class="widget b-t">
|
||||||
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.project_caos_attributes">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<span class="badge bg-warning pull-right">{{project.project_caos_attributes.length}}</span>
|
|
||||||
<h3 translate translate-values="{COUNT:project.project_caos_attributes.length}">{{ 'app.public.projects_show.CAD_file_to_download' }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="widget-content list-group list-group-lg no-bg auto">
|
|
||||||
<li ng-repeat="file in project.project_caos_attributes" class="list-group-item no-b clearfix">
|
|
||||||
<a target="_blank" ng-href="{{file.attachment_url}}" download="{{file.attachment_url}}"><i class="fa fa-arrow-circle-o-down"> </i> {{file.attachment | humanize : 25}}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.status">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<h3 translate>{{ 'app.public.projects_show.status' }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{{ project.status.name }}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.machines">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<span class="badge bg-warning pull-right">{{project.machines.length}}</span>
|
|
||||||
<h3 translate>{{ 'app.public.projects_show.machines_and_materials' }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="widget-content list-group list-group-lg no-bg auto">
|
|
||||||
<li ng-repeat="machine in project.machines" class="list-group-item no-b clearfix">
|
|
||||||
<a ui-sref="app.public.machines_show({id: machine.id})">{{machine.name}}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="widget-content list-group list-group-lg no-bg auto">
|
|
||||||
<li ng-repeat="component in project.components" class="list-group-item no-b clearfix">
|
|
||||||
{{component.name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.project_users.length > 0">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<span class="badge bg-warning pull-right">{{project.project_users.length}}</span>
|
|
||||||
<h3 translate>{{ 'app.public.projects_show.collaborators' }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="widget-content list-group list-group-lg no-bg auto">
|
|
||||||
<li class="list-group-item no-b clearfix block-link" ng-repeat="collaborator in project.project_users" ui-sref="app.logged.members_show({id: collaborator.slug})">
|
|
||||||
<span class="pull-left thumb-sm avatar m-r">
|
|
||||||
<fab-user-avatar ng-model="collaborator.user_avatar" avatar-class="thumb-38"></fab-user-avatar>
|
|
||||||
|
|
||||||
<i class="on b-white bottom" ng-if="collaborator.is_valid"></i>
|
|
||||||
<i class="off b-white bottom" ng-if="!collaborator.is_valid"></i>
|
|
||||||
</span>
|
|
||||||
<span class="clear"><span>{{collaborator.full_name}}</span>
|
|
||||||
<small class="text-muted clear text-ellipsis text-c">{{collaborator.username}}</small>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.licence">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<h3 translate>{{ 'app.public.projects_show.licence' }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{{ project.licence.name }}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.tags">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<h3 translate>{{ 'app.shared.project.tags' }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<pre>{{ project.tags }}</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget panel b-a m" ng-if="project.project_categories">
|
|
||||||
<div class="panel-heading b-b">
|
|
||||||
<h3 translate>{{ projectCategoriesWording }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="widget-content list-group list-group-lg no-bg auto">
|
|
||||||
<li ng-repeat="projectCategory in project.project_categories" class="list-group-item no-b clearfix">
|
|
||||||
{{projectCategory.name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="widget b-t">
|
|
||||||
|
|
||||||
<div class="widget-content text-center m-t">
|
<div class="widget-content text-center m-t">
|
||||||
<a ng-click="signalAbuse($event)"><i class="fa fa-warning"></i> {{ 'app.public.projects_show.report_an_abuse' | translate }}</a>
|
<a ng-click="signalAbuse($event)"><i class="fa fa-warning"></i> {{ 'app.public.projects_show.report_an_abuse' | translate }}</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
@ -5,4 +5,6 @@ class ProjectStep < ApplicationRecord
|
|||||||
belongs_to :project, touch: true
|
belongs_to :project, touch: true
|
||||||
has_many :project_step_images, as: :viewable, dependent: :destroy
|
has_many :project_step_images, as: :viewable, dependent: :destroy
|
||||||
accepts_nested_attributes_for :project_step_images, allow_destroy: true, reject_if: :all_blank
|
accepts_nested_attributes_for :project_step_images, allow_destroy: true, reject_if: :all_blank
|
||||||
|
|
||||||
|
default_scope -> { order(:step_nb) }
|
||||||
end
|
end
|
||||||
|
@ -16,10 +16,14 @@ class ProjectPolicy < ApplicationPolicy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update?
|
def update?
|
||||||
user.admin? or record.author.user_id == user.id or record.users.include?(user)
|
user.admin? || record.author.user_id == user.id || record.users.include?(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def markdown?
|
||||||
|
user.admin? || user.manager? || record.author.user_id == user.id || record.users.include?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy?
|
def destroy?
|
||||||
user.admin? or record.author.user_id == user.id
|
user.admin? || record.author.user_id == user.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
# Provides methods for Project
|
# Provides methods for Project
|
||||||
class ProjectService
|
class ProjectService
|
||||||
def search(params, current_user)
|
def search(params, current_user, paginate: true)
|
||||||
connection = ActiveRecord::Base.connection
|
connection = ActiveRecord::Base.connection
|
||||||
return { error: 'invalid adapter' } unless connection.instance_values['config'][:adapter] == 'postgresql'
|
return { error: 'invalid adapter' } unless connection.instance_values['config'][:adapter] == 'postgresql'
|
||||||
|
|
||||||
search_from_postgre(params, current_user)
|
search_from_postgre(params, current_user, paginate: paginate)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def search_from_postgre(params, current_user)
|
def search_from_postgre(params, current_user, paginate: true)
|
||||||
query_params = JSON.parse(params[:search])
|
query_params = JSON.parse(params[:search] || "{}")
|
||||||
|
|
||||||
records = Project.published_or_drafts(current_user&.statistic_profile&.id)
|
records = Project.published_or_drafts(current_user&.statistic_profile&.id)
|
||||||
records = Project.user_projects(current_user&.statistic_profile&.id) if query_params['from'] == 'mine'
|
records = Project.user_projects(current_user&.statistic_profile&.id) if query_params['from'] == 'mine'
|
||||||
@ -44,6 +44,9 @@ class ProjectService
|
|||||||
records.order(created_at: :desc)
|
records.order(created_at: :desc)
|
||||||
end
|
end
|
||||||
|
|
||||||
{ total: records.count, projects: records.includes(:users, :project_image).page(params[:page]) }
|
records = records.includes(:users, :project_image)
|
||||||
|
records = records.page(params[:page]) if paginate
|
||||||
|
|
||||||
|
{ total: records.count, projects: records }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
88
app/services/project_to_markdown.rb
Normal file
88
app/services/project_to_markdown.rb
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
class ProjectToMarkdown
|
||||||
|
attr_reader :project
|
||||||
|
|
||||||
|
def initialize(project)
|
||||||
|
@project = project
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
md = []
|
||||||
|
|
||||||
|
md << "# #{project.name}"
|
||||||
|
|
||||||
|
md << "![#{I18n.t('app.shared.project.illustration')}](#{full_url(project.project_image.attachment.url)})" if project.project_image
|
||||||
|
|
||||||
|
md << ReverseMarkdown.convert(project.description.to_s)
|
||||||
|
|
||||||
|
project_steps = project.project_steps
|
||||||
|
|
||||||
|
if project_steps.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.steps')}"
|
||||||
|
|
||||||
|
project_steps.each do |project_step|
|
||||||
|
md << "### #{I18n.t('app.shared.project.step_N').gsub('{INDEX}', project_step.step_nb.to_s)} : #{project_step.title}"
|
||||||
|
md << ReverseMarkdown.convert(project_step.description.to_s)
|
||||||
|
|
||||||
|
project_step.project_step_images.each_with_index do |image, i|
|
||||||
|
md << "![#{I18n.t('app.shared.project.step_image')} #{i+1}](#{full_url(project.project_image.attachment.url)})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
md << "## #{I18n.t('app.shared.project.author')}"
|
||||||
|
md << project.author&.user&.profile&.full_name
|
||||||
|
|
||||||
|
if project.themes.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.themes')}"
|
||||||
|
md << project.themes.map(&:name).join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.project_caos.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.CAD_files')}"
|
||||||
|
project.project_caos.each do |cao|
|
||||||
|
md << "![#{cao.attachment_identifier}](#{full_url(cao.attachment_url)})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.status
|
||||||
|
md << "## #{I18n.t('app.shared.project.status')}"
|
||||||
|
md << project.status.name
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.machines.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.employed_machines')}"
|
||||||
|
md << project.machines.map(&:name).join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.components.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.employed_materials')}"
|
||||||
|
md << project.components.map(&:name).join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.users.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.collaborators')}"
|
||||||
|
md << project.users.map { |u| u.profile.full_name }.join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.licence.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.licence')}"
|
||||||
|
md << project.licence.name
|
||||||
|
end
|
||||||
|
|
||||||
|
if project.tags.present?
|
||||||
|
md << "## #{I18n.t('app.shared.project.tags')}"
|
||||||
|
md << project.tags
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
md = md.reject { |line| line.blank? }
|
||||||
|
|
||||||
|
md.join("\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def full_url(path)
|
||||||
|
"#{Rails.application.routes.url_helpers.root_url[...-1]}#{path}"
|
||||||
|
end
|
||||||
|
end
|
22
app/services/projects_archive.rb
Normal file
22
app/services/projects_archive.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
class ProjectsArchive
|
||||||
|
attr_reader :projects
|
||||||
|
|
||||||
|
def initialize(projects)
|
||||||
|
@projects = projects
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
stringio = Zip::OutputStream.write_buffer do |zio|
|
||||||
|
projects.includes(:project_image, :themes,
|
||||||
|
:project_caos, :status, :machines,
|
||||||
|
:components, :licence,
|
||||||
|
project_steps: :project_step_images,
|
||||||
|
author: { user: :profile },
|
||||||
|
users: :profile).find_each do |project|
|
||||||
|
zio.put_next_entry("#{project.name.parameterize}-#{project.id}.md")
|
||||||
|
zio.write ProjectToMarkdown.new(project).call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
stringio.string
|
||||||
|
end
|
||||||
|
end
|
@ -187,6 +187,7 @@ en:
|
|||||||
filter_by_member: "Filter by member"
|
filter_by_member: "Filter by member"
|
||||||
created_from: Created from
|
created_from: Created from
|
||||||
created_to: Created to
|
created_to: Created to
|
||||||
|
download_archive: Download
|
||||||
status_filter:
|
status_filter:
|
||||||
all_statuses: "All statuses"
|
all_statuses: "All statuses"
|
||||||
select_status: "Select a status"
|
select_status: "Select a status"
|
||||||
@ -220,6 +221,7 @@ en:
|
|||||||
report: "Report"
|
report: "Report"
|
||||||
do_you_really_want_to_delete_this_project: "Do you really want to delete this project?"
|
do_you_really_want_to_delete_this_project: "Do you really want to delete this project?"
|
||||||
status: "Status"
|
status: "Status"
|
||||||
|
markdown_file: "Markdown file"
|
||||||
#list of machines
|
#list of machines
|
||||||
machines_list:
|
machines_list:
|
||||||
the_fablab_s_machines: "The machines"
|
the_fablab_s_machines: "The machines"
|
||||||
|
@ -187,6 +187,7 @@ fr:
|
|||||||
filter_by_member: "Filter par membre"
|
filter_by_member: "Filter par membre"
|
||||||
created_from: Créés à partir du
|
created_from: Créés à partir du
|
||||||
created_to: Créés jusqu'au
|
created_to: Créés jusqu'au
|
||||||
|
download_archive: Télécharger
|
||||||
status_filter:
|
status_filter:
|
||||||
all_statuses: "Tous les statuts"
|
all_statuses: "Tous les statuts"
|
||||||
select_status: "Sélectionnez un statut"
|
select_status: "Sélectionnez un statut"
|
||||||
@ -220,6 +221,7 @@ fr:
|
|||||||
report: "Signaler"
|
report: "Signaler"
|
||||||
do_you_really_want_to_delete_this_project: "Êtes-vous sur de vouloir supprimer ce projet ?"
|
do_you_really_want_to_delete_this_project: "Êtes-vous sur de vouloir supprimer ce projet ?"
|
||||||
status: "Statut"
|
status: "Statut"
|
||||||
|
markdown_file: "Fichier Markdown"
|
||||||
#list of machines
|
#list of machines
|
||||||
machines_list:
|
machines_list:
|
||||||
the_fablab_s_machines: "Les machines"
|
the_fablab_s_machines: "Les machines"
|
||||||
|
@ -131,6 +131,7 @@ en:
|
|||||||
illustration: "Visual"
|
illustration: "Visual"
|
||||||
add_an_illustration: "Add an illustration"
|
add_an_illustration: "Add an illustration"
|
||||||
CAD_file: "CAD file"
|
CAD_file: "CAD file"
|
||||||
|
CAD_files: "CAD files"
|
||||||
allowed_extensions: "Allowed extensions:"
|
allowed_extensions: "Allowed extensions:"
|
||||||
add_a_new_file: "Add a new file"
|
add_a_new_file: "Add a new file"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
@ -138,6 +139,7 @@ en:
|
|||||||
steps: "Steps"
|
steps: "Steps"
|
||||||
step_N: "Step {INDEX}"
|
step_N: "Step {INDEX}"
|
||||||
step_title: "Step title"
|
step_title: "Step title"
|
||||||
|
step_image: "Image"
|
||||||
add_a_picture: "Add a picture"
|
add_a_picture: "Add a picture"
|
||||||
change_the_picture: "Change the picture"
|
change_the_picture: "Change the picture"
|
||||||
delete_the_step: "Delete the step"
|
delete_the_step: "Delete the step"
|
||||||
@ -149,7 +151,9 @@ en:
|
|||||||
employed_materials: "Employed materials"
|
employed_materials: "Employed materials"
|
||||||
employed_machines: "Employed machines"
|
employed_machines: "Employed machines"
|
||||||
collaborators: "Collaborators"
|
collaborators: "Collaborators"
|
||||||
|
author: Author
|
||||||
creative_commons_licences: "Creative Commons licences"
|
creative_commons_licences: "Creative Commons licences"
|
||||||
|
licence: "Licence"
|
||||||
themes: "Themes"
|
themes: "Themes"
|
||||||
tags: "Tags"
|
tags: "Tags"
|
||||||
save_as_draft: "Save as draft"
|
save_as_draft: "Save as draft"
|
||||||
|
@ -131,6 +131,7 @@ fr:
|
|||||||
illustration: "Illustration"
|
illustration: "Illustration"
|
||||||
add_an_illustration: "Ajouter un visuel"
|
add_an_illustration: "Ajouter un visuel"
|
||||||
CAD_file: "Fichier CAO"
|
CAD_file: "Fichier CAO"
|
||||||
|
CAD_files: "Fichiers CAO"
|
||||||
allowed_extensions: "Extensions autorisées :"
|
allowed_extensions: "Extensions autorisées :"
|
||||||
add_a_new_file: "Ajouter un nouveau fichier"
|
add_a_new_file: "Ajouter un nouveau fichier"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
@ -138,6 +139,7 @@ fr:
|
|||||||
steps: "Étapes"
|
steps: "Étapes"
|
||||||
step_N: "Étape {INDEX}"
|
step_N: "Étape {INDEX}"
|
||||||
step_title: "Titre de l'étape"
|
step_title: "Titre de l'étape"
|
||||||
|
step_image: "Image"
|
||||||
add_a_picture: "Ajouter une image"
|
add_a_picture: "Ajouter une image"
|
||||||
change_the_picture: "Modifier l'image"
|
change_the_picture: "Modifier l'image"
|
||||||
delete_the_step: "Supprimer l'étape"
|
delete_the_step: "Supprimer l'étape"
|
||||||
@ -149,7 +151,9 @@ fr:
|
|||||||
employed_materials: "Matériaux utilisés"
|
employed_materials: "Matériaux utilisés"
|
||||||
employed_machines: "Machines utilisées"
|
employed_machines: "Machines utilisées"
|
||||||
collaborators: "Les collaborateurs"
|
collaborators: "Les collaborateurs"
|
||||||
|
author: Auteur
|
||||||
creative_commons_licences: "Licences Creative Commons"
|
creative_commons_licences: "Licences Creative Commons"
|
||||||
|
licence: "Licence"
|
||||||
themes: "Thématiques"
|
themes: "Thématiques"
|
||||||
tags: "Étiquettes"
|
tags: "Étiquettes"
|
||||||
save_as_draft: "Enregistrer comme brouillon"
|
save_as_draft: "Enregistrer comme brouillon"
|
||||||
|
@ -38,6 +38,7 @@ Rails.application.routes.draw do
|
|||||||
get :last_published
|
get :last_published
|
||||||
get :search
|
get :search
|
||||||
end
|
end
|
||||||
|
get :markdown, on: :member
|
||||||
end
|
end
|
||||||
resources :openlab_projects, only: :index
|
resources :openlab_projects, only: :index
|
||||||
resources :machines
|
resources :machines
|
||||||
|
2
test/fixtures/project_steps.yml
vendored
2
test/fixtures/project_steps.yml
vendored
@ -7,6 +7,7 @@ project_step_1:
|
|||||||
created_at: 2016-04-04 15:39:08.259759000 Z
|
created_at: 2016-04-04 15:39:08.259759000 Z
|
||||||
updated_at: 2016-04-04 15:39:08.259759000 Z
|
updated_at: 2016-04-04 15:39:08.259759000 Z
|
||||||
title: Le manche
|
title: Le manche
|
||||||
|
step_nb: 1
|
||||||
|
|
||||||
project_step_2:
|
project_step_2:
|
||||||
id: 2
|
id: 2
|
||||||
@ -16,3 +17,4 @@ project_step_2:
|
|||||||
created_at: 2016-04-04 15:39:08.265840000 Z
|
created_at: 2016-04-04 15:39:08.265840000 Z
|
||||||
updated_at: 2016-04-04 15:39:08.265840000 Z
|
updated_at: 2016-04-04 15:39:08.265840000 Z
|
||||||
title: La presse
|
title: La presse
|
||||||
|
step_nb: 2
|
1
test/fixtures/projects.yml
vendored
1
test/fixtures/projects.yml
vendored
@ -12,3 +12,4 @@ project_1:
|
|||||||
state: published
|
state: published
|
||||||
slug: presse-puree
|
slug: presse-puree
|
||||||
published_at: 2016-04-04 15:39:08.267614000 Z
|
published_at: 2016-04-04 15:39:08.267614000 Z
|
||||||
|
status_id: 1
|
17
test/integration/projects_test.rb
Normal file
17
test/integration/projects_test.rb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ProjectsTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@admin = User.find_by(username: 'admin')
|
||||||
|
login_as(@admin, scope: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'download markdown file' do
|
||||||
|
get "/api/projects/1/markdown"
|
||||||
|
|
||||||
|
assert_response :success
|
||||||
|
assert_equal "text/markdown", response.content_type
|
||||||
|
end
|
||||||
|
end
|
21
test/services/project_to_markdown_test.rb
Normal file
21
test/services/project_to_markdown_test.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ProjectToMarkdownTest < ActiveSupport::TestCase
|
||||||
|
test "ProjectToMarkdown is working" do
|
||||||
|
project = projects(:project_1)
|
||||||
|
service = ProjectToMarkdown.new(project)
|
||||||
|
|
||||||
|
markdown_str = nil
|
||||||
|
|
||||||
|
assert_nothing_raised do
|
||||||
|
markdown_str = service.call
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_includes markdown_str, project.name
|
||||||
|
project.project_steps.each do |project_step|
|
||||||
|
assert_includes markdown_str, project_step.title
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user