kopia lustrzana https://github.com/OpenDroneMap/WebODM
Sharing feature working, still needs unit testing
rodzic
39c391451f
commit
2bc61c2633
|
@ -9,6 +9,7 @@ from django.db.models.functions import Cast
|
|||
from django.http import HttpResponse
|
||||
from wsgiref.util import FileWrapper
|
||||
from rest_framework import status, serializers, viewsets, filters, exceptions, permissions, parsers
|
||||
from rest_framework.permissions import IsAuthenticatedOrReadOnly
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import detail_route
|
||||
from rest_framework.views import APIView
|
||||
|
@ -36,7 +37,7 @@ class TaskSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = models.Task
|
||||
exclude = ('processing_lock', 'console_output', 'orthophoto_extent', 'dsm_extent', 'dtm_extent', )
|
||||
read_only_fields = ('processing_time', 'status', 'last_error', 'created_at', 'pending_action', 'available_assets', 'public_uuid', )
|
||||
read_only_fields = ('processing_time', 'status', 'last_error', 'created_at', 'pending_action', 'available_assets', )
|
||||
|
||||
class TaskViewSet(viewsets.ViewSet):
|
||||
"""
|
||||
|
@ -171,6 +172,7 @@ class TaskViewSet(viewsets.ViewSet):
|
|||
|
||||
class TaskNestedView(APIView):
|
||||
queryset = models.Task.objects.all().defer('orthophoto_extent', 'dtm_extent', 'dsm_extent', 'console_output', )
|
||||
permission_classes = (IsAuthenticatedOrReadOnly, )
|
||||
|
||||
def get_and_check_task(self, request, pk, project_pk, annotate={}):
|
||||
try:
|
||||
|
|
|
@ -447,6 +447,17 @@ class Task(models.Model):
|
|||
}
|
||||
}
|
||||
|
||||
def get_model_display_params(self):
|
||||
"""
|
||||
Subset of a task fields used in the 3D model display view
|
||||
"""
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'project': self.project.id,
|
||||
'available_assets': self.available_assets,
|
||||
'public': self.public
|
||||
}
|
||||
|
||||
def generate_deferred_asset(self, archive, directory):
|
||||
"""
|
||||
:param archive: path of the destination .zip file (relative to /assets/ directory)
|
||||
|
|
|
@ -6,6 +6,37 @@ html, body, section.main, .content, #wrapper, #page-wrapper{
|
|||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
#public-wrapper{
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
position: relative;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
#iframe{
|
||||
.map-view{
|
||||
height: 100%;
|
||||
.map-type-selector{
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
float: none;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.switchModeButton{
|
||||
bottom: 22px;
|
||||
}
|
||||
.opacity-slider{
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
[data-mapview], .model-view{
|
||||
height: calc(100vh);
|
||||
}
|
||||
}
|
||||
|
||||
#navbar-top{
|
||||
height: 50px;
|
||||
min-height: 50px;
|
||||
|
|
|
@ -8,13 +8,15 @@ class MapView extends React.Component {
|
|||
static defaultProps = {
|
||||
mapItems: [],
|
||||
selectedMapType: 'orthophoto',
|
||||
title: ""
|
||||
title: "",
|
||||
public: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
mapItems: PropTypes.array.isRequired, // list of dictionaries where each dict is a {mapType: 'orthophoto', url: <tiles.json>},
|
||||
selectedMapType: PropTypes.oneOf(['orthophoto', 'dsm', 'dtm']),
|
||||
title: PropTypes.string,
|
||||
public: PropTypes.bool
|
||||
};
|
||||
|
||||
constructor(props){
|
||||
|
@ -101,7 +103,8 @@ class MapView extends React.Component {
|
|||
tiles={this.state.tiles}
|
||||
showBackground={true}
|
||||
opacity={opacity}
|
||||
mapType={this.state.selectedMapType} />
|
||||
mapType={this.state.selectedMapType}
|
||||
public={this.props.public} />
|
||||
<div className="opacity-slider theme-secondary">
|
||||
Opacity: <input type="range" step="1" value={opacity} onChange={this.updateOpacity} />
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import ErrorMessage from './components/ErrorMessage';
|
|||
import SwitchModeButton from './components/SwitchModeButton';
|
||||
import AssetDownloadButtons from './components/AssetDownloadButtons';
|
||||
import Standby from './components/Standby';
|
||||
import ShareButton from './components/ShareButton';
|
||||
import PropTypes from 'prop-types';
|
||||
import $ from 'jquery';
|
||||
|
||||
|
@ -15,11 +16,13 @@ import Potree from './vendor/potree';
|
|||
|
||||
class ModelView extends React.Component {
|
||||
static defaultProps = {
|
||||
task: null
|
||||
task: null,
|
||||
public: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
task: PropTypes.object.isRequired, // The object should contain two keys: {id: <taskId>, project: <projectId>}
|
||||
public: PropTypes.bool // Is the view being displayed via a shared link?
|
||||
};
|
||||
|
||||
constructor(props){
|
||||
|
@ -35,6 +38,7 @@ class ModelView extends React.Component {
|
|||
this.modelReference = null;
|
||||
|
||||
this.toggleTexturedModel = this.toggleTexturedModel.bind(this);
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||
}
|
||||
|
||||
assetsPath(){
|
||||
|
@ -66,6 +70,11 @@ class ModelView extends React.Component {
|
|||
return 'odm_textured_model.mtl';
|
||||
}
|
||||
|
||||
handleMouseDown(e){
|
||||
// Make sure the share popup closes
|
||||
this.shareButton.hidePopup();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let container = this.container;
|
||||
|
||||
|
@ -179,7 +188,6 @@ class ModelView extends React.Component {
|
|||
className="container"
|
||||
style={{height: "100%", width: "100%", position: "relative"}}
|
||||
onContextMenu={(e) => {e.preventDefault();}}>
|
||||
|
||||
<div
|
||||
id="potree_render_area"
|
||||
ref={(domNode) => { this.container = domNode; }}>
|
||||
|
@ -190,7 +198,7 @@ class ModelView extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="potree_sidebar_container">
|
||||
<div id="potree_sidebar_container" onMouseDown={this.handleMouseDown}>
|
||||
|
||||
<div id="sidebar_root"
|
||||
className="navmenu navmenu-default navmenu-fixed-left unselectable">
|
||||
|
@ -210,10 +218,23 @@ class ModelView extends React.Component {
|
|||
task={this.props.task}
|
||||
direction="down"
|
||||
buttonClass="btn-secondary" />
|
||||
{showSwitchModeButton ?
|
||||
<SwitchModeButton
|
||||
task={this.props.task}
|
||||
type="modelToMap" /> : ""}
|
||||
|
||||
<div className="action-buttons-row">
|
||||
{(!this.props.public) ?
|
||||
<ShareButton
|
||||
ref={(ref) => { this.shareButton = ref; }}
|
||||
task={this.props.task}
|
||||
popupPlacement="bottom"
|
||||
linksTarget="3d"
|
||||
/>
|
||||
: ""}
|
||||
{showSwitchModeButton ?
|
||||
<SwitchModeButton
|
||||
public={this.props.public}
|
||||
style={{marginLeft: this.props.public ? '0' : '76px'}}
|
||||
task={this.props.task}
|
||||
type="modelToMap" /> : ""}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="accordion">
|
||||
|
|
|
@ -33,7 +33,7 @@ class ClipboardInput extends React.Component{
|
|||
onBlur={() => { this.setState({showCopied: false}); }}
|
||||
/>
|
||||
<div style={{position: 'relative', 'width': '100%'}}>
|
||||
<div className={"copied theme-background-success " + (this.state.showCopied ? "show" : "")}>Copied to clipboard!</div>
|
||||
<div className={"copied theme-background-success " + (this.state.showCopied ? "show" : "")}>Copied to clipboard</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ class Map extends React.Component {
|
|||
minzoom: 0,
|
||||
showBackground: false,
|
||||
opacity: 100,
|
||||
mapType: "orthophoto"
|
||||
mapType: "orthophoto",
|
||||
public: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
|
@ -33,7 +34,8 @@ class Map extends React.Component {
|
|||
showBackground: PropTypes.bool,
|
||||
tiles: PropTypes.array.isRequired,
|
||||
opacity: PropTypes.number,
|
||||
mapType: PropTypes.oneOf(['orthophoto', 'dsm', 'dtm'])
|
||||
mapType: PropTypes.oneOf(['orthophoto', 'dsm', 'dtm']),
|
||||
public: PropTypes.bool
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -276,15 +278,17 @@ class Map extends React.Component {
|
|||
|
||||
|
||||
<div className="actionButtons">
|
||||
{this.state.singleTask !== null ?
|
||||
{(!this.props.public && this.state.singleTask !== null) ?
|
||||
<ShareButton
|
||||
ref={(ref) => { this.shareButton = ref; }}
|
||||
task={this.state.singleTask}
|
||||
linksTarget="map"
|
||||
/>
|
||||
: ""}
|
||||
<SwitchModeButton
|
||||
task={this.state.singleTask}
|
||||
type="mapToModel" />
|
||||
type="mapToModel"
|
||||
public={this.props.public} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -7,9 +7,12 @@ import $ from 'jquery';
|
|||
class ShareButton extends React.Component {
|
||||
static defaultProps = {
|
||||
task: null,
|
||||
popupPlacement: 'top'
|
||||
};
|
||||
static propTypes = {
|
||||
task: PropTypes.object.isRequired
|
||||
task: PropTypes.object.isRequired,
|
||||
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
||||
popupPlacement: PropTypes.string
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
|
@ -37,14 +40,17 @@ class ShareButton extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="shareButton" onClick={e => { e.stopPropagation(); }}>
|
||||
{this.state.showPopup ?
|
||||
<SharePopup
|
||||
const popup = <SharePopup
|
||||
task={this.state.task}
|
||||
taskChanged={this.handleTaskChanged}
|
||||
/>
|
||||
: ""}
|
||||
placement={this.props.popupPlacement}
|
||||
linksTarget={this.props.linksTarget}
|
||||
/>;
|
||||
|
||||
return (
|
||||
<div className="shareButton" onClick={e => { e.stopPropagation(); }}>
|
||||
{this.props.popupPlacement === 'top' && this.state.showPopup ?
|
||||
popup : ""}
|
||||
<button
|
||||
ref={(domNode) => { this.shareButton = domNode; }}
|
||||
type="button"
|
||||
|
@ -52,6 +58,8 @@ class ShareButton extends React.Component {
|
|||
className={"shareButton btn btn-sm " + (this.state.task.public ? "btn-primary" : "btn-secondary")}>
|
||||
<i className="fa fa-share-alt"></i> Share
|
||||
</button>
|
||||
{this.props.popupPlacement === 'bottom' && this.state.showPopup ?
|
||||
popup : ""}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,12 @@ import ClipboardInput from './ClipboardInput';
|
|||
class SharePopup extends React.Component{
|
||||
static propTypes = {
|
||||
task: PropTypes.object.isRequired,
|
||||
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
||||
placement: PropTypes.string,
|
||||
taskChanged: PropTypes.func
|
||||
};
|
||||
static defaultProps = {
|
||||
placement: 'top',
|
||||
taskChanged: () => {}
|
||||
};
|
||||
|
||||
|
@ -57,11 +60,12 @@ class SharePopup extends React.Component{
|
|||
}
|
||||
|
||||
render(){
|
||||
const shareLink = Utils.absoluteUrl(`/public/task/${this.state.task.id}/map/`);
|
||||
const iframeUrl = Utils.absoluteUrl(`public/task/${this.state.task.id}/iframe/`);
|
||||
const shareLink = Utils.absoluteUrl(`/public/task/${this.state.task.id}/${this.props.linksTarget}/`);
|
||||
const iframeUrl = Utils.absoluteUrl(`public/task/${this.state.task.id}/iframe/${this.props.linksTarget}/`);
|
||||
const iframeCode = `<iframe>${iframeUrl}</iframe>`;
|
||||
|
||||
return (<div className="sharePopup popover top in">
|
||||
return (<div onMouseDown={e => { e.stopPropagation(); }}
|
||||
className={"sharePopup popover in " + this.props.placement}>
|
||||
<div className="arrow"></div>
|
||||
<h3 className="popover-title theme-background-highlight">Share This Task</h3>
|
||||
<div className="popover-content theme-secondary">
|
||||
|
@ -77,8 +81,7 @@ class SharePopup extends React.Component{
|
|||
type="checkbox"
|
||||
checked={this.state.task.public}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
Enabled
|
||||
/> Enabled
|
||||
</label>
|
||||
</div>
|
||||
<div className={"share-links " + (this.state.task.public ? "show" : "")}>
|
||||
|
|
|
@ -5,12 +5,16 @@ import PropTypes from 'prop-types';
|
|||
class SwitchModeButton extends React.Component {
|
||||
static defaultProps = {
|
||||
task: null,
|
||||
type: "mapToModel"
|
||||
type: "mapToModel",
|
||||
public: false,
|
||||
style: {}
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
task: PropTypes.object, // The object should contain two keys: {id: <taskId>, project: <projectId>}
|
||||
type: PropTypes.string // Either "mapToModel" or "modelToMap"
|
||||
type: PropTypes.string, // Either "mapToModel" or "modelToMap"
|
||||
public: PropTypes.bool, // Whether to use public or private URLs
|
||||
style: PropTypes.object
|
||||
};
|
||||
|
||||
constructor(props){
|
||||
|
@ -24,8 +28,13 @@ class SwitchModeButton extends React.Component {
|
|||
|
||||
handleClick(){
|
||||
if (this.props.task){
|
||||
const prefix = this.props.type === 'mapToModel' ? '3d' : 'map';
|
||||
location.href = `/${prefix}/project/${this.props.task.project}/task/${this.props.task.id}/`;
|
||||
const target = this.props.type === 'mapToModel' ? '3d' : 'map';
|
||||
|
||||
let url = this.props.public ?
|
||||
`../${target}/`
|
||||
: `/${target}/project/${this.props.task.project}/task/${this.props.task.id}/`;
|
||||
|
||||
location.href = url;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +49,7 @@ class SwitchModeButton extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<button
|
||||
style={this.props.style}
|
||||
onClick={this.handleClick}
|
||||
type="button"
|
||||
className={"switchModeButton btn btn-sm btn-secondary " + (!this.props.task ? "hide" : "")}>
|
||||
|
|
|
@ -5,7 +5,7 @@ const taskMock = require('../../tests/utils/MockLoader').load("task.json");
|
|||
|
||||
describe('<ShareButton />', () => {
|
||||
it('renders without exploding', () => {
|
||||
const wrapper = shallow(<ShareButton task={taskMock} />);
|
||||
const wrapper = shallow(<ShareButton task={taskMock} linksTarget="map" />);
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
})
|
||||
});
|
|
@ -5,7 +5,7 @@ const taskMock = require('../../tests/utils/MockLoader').load("task.json");
|
|||
|
||||
describe('<SharePopup />', () => {
|
||||
it('renders without exploding', () => {
|
||||
const wrapper = shallow(<SharePopup task={taskMock} />);
|
||||
const wrapper = shallow(<SharePopup task={taskMock} linksTarget="map" />);
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
})
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
.clipboardInput{
|
||||
text-align: center;
|
||||
|
||||
|
||||
.copied{
|
||||
position: absolute;
|
||||
font-size: 70%;
|
||||
|
|
|
@ -21,4 +21,10 @@
|
|||
.popup-opacity-slider{
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.shareButton{
|
||||
z-index: 2000;
|
||||
bottom: -11px;
|
||||
right: 38px;
|
||||
}
|
||||
}
|
|
@ -67,6 +67,15 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons-row{
|
||||
margin-top: 12px;
|
||||
|
||||
& > *{
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
.shareButton{
|
||||
position: absolute;
|
||||
z-index: 2000;
|
||||
bottom: -11px;
|
||||
right: 38px;
|
||||
|
||||
position: absolute;
|
||||
button{
|
||||
border-width: 1px;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
.sharePopup{
|
||||
position: relative;
|
||||
top: -32px;
|
||||
display: block;
|
||||
|
||||
&.top{
|
||||
top: -32px;
|
||||
}
|
||||
&.bottom{
|
||||
top: 32px;
|
||||
}
|
||||
|
||||
&.popover.top > .arrow{
|
||||
left: auto;
|
||||
right: 60px;
|
||||
}
|
||||
&.popover.bottom > .arrow{
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
h3.popover-title{
|
||||
padding-top: 8px;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body data-admin-utc-offset="{% now "Z" %}">
|
||||
{% block body %}
|
||||
<!--[if lt IE 8]>
|
||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
|
@ -78,6 +79,7 @@
|
|||
{% autoescape off %}
|
||||
{% get_footer %}
|
||||
{% endautoescape %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
<script src="{% static 'app/js/vendor/metisMenu.min.js' %}"></script>
|
||||
<script>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{% extends "app/public/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% render_bundle 'ModelView' attrs='async' %}
|
||||
|
||||
<h3><i class="fa fa-cube"></i> {{title}}</h3>
|
||||
|
||||
<div data-modelview
|
||||
{% for key, value in params %}
|
||||
data-{{key}}="{{value}}"
|
||||
{% endfor %}
|
||||
></div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "app/public/iframe_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% render_bundle 'ModelView' attrs='async' %}
|
||||
|
||||
<div data-modelview
|
||||
{% for key, value in params %}
|
||||
data-{{key}}="{{value}}"
|
||||
{% endfor %}
|
||||
></div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,9 @@
|
|||
{% extends "app/base.html" %}
|
||||
|
||||
{% block page-wrapper %}
|
||||
{{ SETTINGS.theme.html_after_header|safe }}
|
||||
|
||||
<div id="public-wrapper">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
{% extends "app/base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<div id="iframe">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,7 +1,6 @@
|
|||
{% extends "app/base.html" %}
|
||||
{% load i18n %}
|
||||
{% extends "app/public/base.html" %}
|
||||
|
||||
{% block page-wrapper %}
|
||||
{% block content %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% render_bundle 'MapView' attrs='async' %}
|
||||
|
||||
|
@ -10,6 +9,4 @@
|
|||
data-{{key}}="{{value}}"
|
||||
{% endfor %}
|
||||
></div>
|
||||
|
||||
{{ SETTINGS.theme.html_after_header|safe }}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "app/public/iframe_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% render_bundle 'MapView' attrs='async' %}
|
||||
<div data-mapview
|
||||
{% for key, value in params %}
|
||||
data-{{key}}="{{value}}"
|
||||
{% endfor %}
|
||||
></div>
|
||||
{% endblock %}
|
|
@ -13,7 +13,10 @@ urlpatterns = [
|
|||
url(r'^map/project/(?P<project_pk>[^/.]+)/$', private_views.map, name='map'),
|
||||
url(r'^3d/project/(?P<project_pk>[^/.]+)/task/(?P<task_pk>[^/.]+)/$', private_views.model_display, name='model_display'),
|
||||
|
||||
url(r'^public/map/(?P<task_public_uuid>[^/.]+)/$', public_views.map, name='public_map'),
|
||||
url(r'^public/task/(?P<task_pk>[^/.]+)/map/$', public_views.map, name='public_map'),
|
||||
url(r'^public/task/(?P<task_pk>[^/.]+)/iframe/map/$', public_views.map_iframe, name='public_map'),
|
||||
url(r'^public/task/(?P<task_pk>[^/.]+)/3d/$', public_views.model_display, name='public_map'),
|
||||
url(r'^public/task/(?P<task_pk>[^/.]+)/iframe/3d/$', public_views.model_display_iframe, name='public_map'),
|
||||
|
||||
url(r'^processingnode/([\d]+)/$', private_views.processing_node, name='processing_node'),
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ def map(request, project_pk=None, task_pk=None):
|
|||
'title': title,
|
||||
'params': {
|
||||
'map-items': json.dumps(mapItems),
|
||||
'title': title
|
||||
'title': title,
|
||||
'public': 'false'
|
||||
}.items()
|
||||
})
|
||||
|
||||
|
@ -80,15 +81,12 @@ def model_display(request, project_pk=None, task_pk=None):
|
|||
raise Http404()
|
||||
|
||||
return render(request, 'app/3d_model_display.html', {
|
||||
'title': title,
|
||||
'params': {
|
||||
'task': json.dumps({
|
||||
'id': str(task.id),
|
||||
'project': project.id,
|
||||
'available_assets': task.available_assets
|
||||
})
|
||||
}.items()
|
||||
})
|
||||
'title': title,
|
||||
'params': {
|
||||
'task': json.dumps(task.get_model_display_params()),
|
||||
'public': 'false'
|
||||
}.items()
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -7,23 +7,46 @@ from django.shortcuts import render
|
|||
from app.models import Task
|
||||
|
||||
|
||||
def get_public_task(public_uuid):
|
||||
def get_public_task(task_pk):
|
||||
"""
|
||||
Get a task and raise a 404 if it's not public
|
||||
"""
|
||||
task = get_object_or_404(Task, public_uuid=public_uuid)
|
||||
#if not task.public:
|
||||
# raise Http404()
|
||||
task = get_object_or_404(Task, pk=task_pk)
|
||||
if not task.public:
|
||||
raise Http404()
|
||||
return task
|
||||
|
||||
def handle_map(request, template, task_pk=None, hide_title=False):
|
||||
task = get_public_task(task_pk)
|
||||
|
||||
def map(request, task_public_uuid=None):
|
||||
task = get_public_task(task_public_uuid)
|
||||
|
||||
return render(request, 'app/map.html', {
|
||||
return render(request, template, {
|
||||
'title': _("Map"),
|
||||
'params': {
|
||||
'map-items': json.dumps([task.get_map_items()]),
|
||||
'title': task.name
|
||||
'title': task.name if not hide_title else '',
|
||||
'public': 'true'
|
||||
}.items()
|
||||
})
|
||||
})
|
||||
|
||||
def map(request, task_pk=None):
|
||||
return handle_map(request, 'app/public/map.html', task_pk, False)
|
||||
|
||||
def map_iframe(request, task_pk=None):
|
||||
return handle_map(request, 'app/public/map_iframe.html', task_pk, True)
|
||||
|
||||
def handle_model_display(request, template, task_pk=None):
|
||||
task = get_public_task(task_pk)
|
||||
|
||||
return render(request, template, {
|
||||
'title': task.name,
|
||||
'params': {
|
||||
'task': json.dumps(task.get_model_display_params()),
|
||||
'public': 'true'
|
||||
}.items()
|
||||
})
|
||||
|
||||
def model_display(request, task_pk=None):
|
||||
return handle_model_display(request, 'app/public/3d_model_display.html', task_pk)
|
||||
|
||||
def model_display_iframe(request, task_pk=None):
|
||||
return handle_model_display(request, 'app/public/3d_model_display_iframe.html', task_pk)
|
Ładowanie…
Reference in New Issue