source: main/branches/3D/openPLM/plmapp/views/main.py @ 662

Revision 662, 45.6 KB checked in by pcosquer, 9 years ago (diff)

3D branch: merge changes from trunk (rev [661])

  • Property svn:executable set to *
Line 
1#-!- coding:utf-8 -!-
2
3############################################################################
4# openPLM - open source PLM
5# Copyright 2010 Philippe Joulaud, Pierre Cosquer
6#
7# This file is part of openPLM.
8#
9#    openPLM is free software: you can redistribute it and/or modify
10#    it under the terms of the GNU General Public License as published by
11#    the Free Software Foundation, either version 3 of the License, or
12#    (at your option) any later version.
13#
14#    openPLM is distributed in the hope that it will be useful,
15#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17#    GNU General Public License for more details.
18#
19#    You should have received a copy of the GNU General Public License
20#    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
21#
22# Contact :
23#    Philippe Joulaud : ninoo.fr@gmail.com
24#    Pierre Cosquer : pierre.cosquer@insa-rennes.fr
25################################################################################
26
27"""
28Introduction
29=============
30
31This module contains all views to display html pages.
32
33All URLs are linked with django's standard views or with plmapp view functions hereafter.
34Each of them receives an httprequest object.
35Then treat data with the help of different controllers and different models.
36Then adress a html template with a context dictionnary via an httpresponse.
37
38We have a view for each :class:`PLMObject` or :class:`UserProfile` :func:`menu_items`.
39We have some views which allow link creation between 2 instances of :class:`PLMObject` or between
40an instance of :class:`PLMObject` and an instance of :class:`UserProfile`.
41We have some views for link deletion.
42We have some views for link edition.
43We have views for :class:`PLMObject` creation and edition.
44Finaly we have :func:`navigate` which draw a picture with a central object and its related objects.
45
46"""
47
48import os
49import csv
50import datetime
51import tempfile
52import itertools
53from operator import attrgetter
54from mimetypes import guess_type
55
56from django.shortcuts import render_to_response
57from django.http import HttpResponseRedirect, HttpResponse,\
58                        HttpResponsePermanentRedirect, HttpResponseForbidden
59from django.template import RequestContext
60from django.contrib.auth.forms import PasswordChangeForm
61from django.utils.encoding import iri_to_uri
62from django.utils.translation import ugettext_lazy as _
63from django.forms import HiddenInput
64
65from openPLM.plmapp.archive import generate_archive
66from openPLM.plmapp.exceptions import ControllerError, PermissionError
67import openPLM.plmapp.models as models
68from openPLM.plmapp.controllers import get_controller
69from openPLM.plmapp.utils import level_to_sign_str, get_next_revision
70from openPLM.plmapp.forms import *
71import openPLM.plmapp.forms as forms
72from openPLM.plmapp.base_views import get_obj, get_obj_from_form, \
73    get_obj_by_id, handle_errors, get_generic_data, get_navigate_data
74import openPLM.plmapp.csvimport as csvimport
75
76def r2r(template, dictionary, request):
77    """
78    Shortcut for:
79   
80    ::
81       
82        render_to_response(template, dictionary,
83                              context_instance=RequestContext(request))
84    """
85    return render_to_response(template, dictionary,
86                              context_instance=RequestContext(request))
87
88##########################################################################################
89###                    Function which manage the html home page                        ###
90##########################################################################################
91@handle_errors
92def display_home_page(request):
93    """
94    Once the user is logged in, redirection to his/her own user object with :func:navigate
95    """
96    return HttpResponseRedirect("/user/%s/navigate/" % request.user)
97
98#############################################################################################
99###All functions which manage the different html pages related to a part, a doc and a user###
100#############################################################################################
101@handle_errors
102def display_object_attributes(request, obj_type, obj_ref, obj_revi):
103    """
104    Manage html page which displays attributes of the selected object.
105    It computes a context dictionnary based on
106   
107    .. include:: views_params.txt
108    """
109    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
110   
111    object_attributes_list = []
112    for attr in obj.attributes:
113        item = obj.get_verbose_name(attr)
114        object_attributes_list.append((item, getattr(obj, attr)))
115    ctx.update({'current_page' : 'attributes',
116                'object_attributes': object_attributes_list})
117    return r2r('DisplayObject.htm', ctx, request)
118
119##########################################################################################
120@handle_errors
121def display_object(request, obj_type, obj_ref, obj_revi):
122    """
123    Manage html page which displays attributes of the selected object.
124    Redirection to :func:display_object_attributes
125    """
126     
127    if obj_type in ('User', 'Group'):
128        url = u"/%s/%s/attributes/" % (obj_type.lower(), obj_ref)
129    else:
130        model_cls = models.get_all_plmobjects()[obj_type]
131        page = "files" if issubclass(model_cls, models.Document) else "attributes"
132        url = u"/object/%s/%s/%s/%s/" % (obj_type, obj_ref, obj_revi, page)
133    return HttpResponsePermanentRedirect(iri_to_uri(url))
134
135##########################################################################################
136@handle_errors
137def display_object_lifecycle(request, obj_type, obj_ref, obj_revi):
138    """
139    Manage html page which displays lifecycle of the selected object.
140    It computes a context dictionnary based on
141   
142    .. include:: views_params.txt
143    """
144    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
145    if request.method == 'POST':
146        if request.POST["action"] == "DEMOTE":
147            obj.demote()
148        elif request.POST["action"] == "PROMOTE":
149            obj.promote()
150   
151    state = obj.state.name
152    object_lifecycle = []
153    for st in obj.lifecycle:
154        object_lifecycle.append((st, st == state))
155    is_signer = obj.check_permission(obj.get_current_sign_level(), False)
156    is_signer_dm = obj.check_permission(obj.get_previous_sign_level(), False)
157    ctx.update({'current_page':'lifecycle',
158                'object_lifecycle': object_lifecycle,
159                'is_signer' : is_signer,
160                'is_signer_dm' : is_signer_dm})
161    return r2r('DisplayObjectLifecycle.htm', ctx, request)
162
163##########################################################################################
164@handle_errors
165def display_object_revisions(request, obj_type, obj_ref, obj_revi):
166    """
167    Manage html page which displays all revisions of the selected object.
168    It computes a context dictionnary based on
169   
170    .. include:: views_params.txt
171    """
172    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
173   
174    if obj.is_revisable():
175        if request.method == "POST" and request.POST:
176            add_form = AddRevisionForm(request.POST)
177            if add_form.is_valid():
178                obj.revise(add_form.cleaned_data["revision"])
179        else:
180            add_form = AddRevisionForm({"revision" : get_next_revision(obj_revi)})
181        ctx["add_revision_form"] = add_form
182    revisions = obj.get_all_revisions()
183    ctx.update({'current_page' : 'revisions',
184                'revisions' : revisions,
185                })
186    return r2r('DisplayObjectRevisions.htm', ctx, request)
187
188##########################################################################################
189@handle_errors
190def display_object_history(request, obj_type, obj_ref, obj_revi):
191    """
192    Manage html page which displays the history of the selected object.
193    It computes a context dictionnary based on
194   
195    .. include:: views_params.txt
196    """
197    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
198    history = obj.HISTORY.objects.filter(plmobject=obj.object).order_by('-date')
199    ctx.update({'current_page' : 'history',
200                'object_history' : list(history)})
201    return r2r('DisplayObjectHistory.htm', ctx, request)
202
203#############################################################################################
204###         All functions which manage the different html pages specific to part          ###
205#############################################################################################
206@handle_errors
207def display_object_child(request, obj_type, obj_ref, obj_revi):
208    """
209    Manage html page which displays the chidren of the selected object.
210    It computes a context dictionnary based on
211   
212    .. include:: views_params.txt
213    """
214    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
215   
216    if not hasattr(obj, "get_children"):
217        # TODO
218        raise TypeError()
219    date = None
220    level = "first"
221    if request.GET:
222        display_form = DisplayChildrenForm(request.GET)
223        if display_form.is_valid():
224            date = display_form.cleaned_data["date"]
225            level = display_form.cleaned_data["level"]
226    else:
227        display_form = DisplayChildrenForm(initial={"date" : datetime.datetime.now(),
228                                                    "level" : "first"})
229    max_level = 1 if level == "first" else -1
230    children = obj.get_children(max_level, date=date)
231    if level == "last" and children:
232        maximum = max(children, key=attrgetter("level")).level
233        children = (c for c in children if c.level == maximum)
234    # convert level to html space
235    #children = (("&nbsp;" * 2 * (level-1), link) for level, link in children)
236
237    ctx.update({'current_page':'BOM-child',
238                'children': children,
239                "display_form" : display_form})
240    return r2r('DisplayObjectChild.htm', ctx, request)
241
242##########################################################################################
243@handle_errors(undo="..")
244def edit_children(request, obj_type, obj_ref, obj_revi):
245    """
246    Manage html page which edits the chidren of the selected object.
247    Possibility to modify the `.ParentChildLink.order`, the `.ParentChildLink.quantity` and to
248    desactivate the `.ParentChildLink`
249    It computes a context dictionnary based on
250   
251    .. include:: views_params.txt
252    """
253    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
254   
255    if not hasattr(obj, "get_children"):
256        # TODO
257        raise TypeError()
258    if request.method == "POST":
259        formset = get_children_formset(obj, request.POST)
260        if formset.is_valid():
261            obj.update_children(formset)
262            return HttpResponseRedirect("..")
263    else:
264        formset = get_children_formset(obj)
265    ctx.update({'current_page':'BOM-child',
266                'children_formset': formset, })
267    return r2r('DisplayObjectChildEdit.htm', ctx, request)
268
269##########################################################################################   
270@handle_errors
271def add_children(request, obj_type, obj_ref, obj_revi):
272    """
273    Manage html page for chidren creation of the selected object.
274    It computes a context dictionnary based on
275   
276    .. include:: views_params.txt
277    """
278    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
279   
280    if request.POST:
281        add_child_form = AddChildForm(request.POST)
282        if add_child_form.is_valid():
283            child_obj = get_obj_from_form(add_child_form, request.user)
284            obj.add_child(child_obj,
285                          add_child_form.cleaned_data["quantity"],
286                          add_child_form.cleaned_data["order"],
287                          add_child_form.cleaned_data["unit"])
288            return HttpResponseRedirect(obj.plmobject_url + "BOM-child/")
289    else:
290        add_child_form = AddChildForm()
291        ctx['current_page'] = 'BOM-child'
292    ctx.update({'link_creation': True,
293                'add_child_form': add_child_form,
294                'attach' : (obj, "add_child")})
295    return r2r('DisplayObjectChildAdd.htm', ctx, request)
296   
297##########################################################################################   
298@handle_errors
299def display_object_parents(request, obj_type, obj_ref, obj_revi):
300    """
301    Manage html page which displays the parent of the selected object.
302    It computes a context dictionnary based on
303   
304    .. include:: views_params.txt
305    """
306    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
307   
308    if not hasattr(obj, "get_parents"):
309        # TODO
310        raise TypeError()
311    date = None
312    level = "first"
313    if request.GET:
314        display_form = DisplayChildrenForm(request.GET)
315        if display_form.is_valid():
316            date = display_form.cleaned_data["date"]
317            level = display_form.cleaned_data["level"]
318    else:
319        display_form = DisplayChildrenForm(initial={"date" : datetime.datetime.now(),
320                                                    "level" : "first"})
321    max_level = 1 if level == "first" else -1
322    parents = obj.get_parents(max_level, date=date)
323    if level == "last" and parents:
324        maximum = max(parents, key=attrgetter("level")).level
325        parents = (c for c in parents if c.level == maximum)
326    ctx.update({'current_page':'parents',
327                'parents' :  parents,
328                'display_form' : display_form, })
329    return r2r('DisplayObjectParents.htm', ctx, request)
330
331##########################################################################################
332@handle_errors
333def display_object_doc_cad(request, obj_type, obj_ref, obj_revi):
334    """
335    Manage html page which displays the related documents and CAD of
336    the selected object.
337    It computes a context dictionnary based on
338   
339    .. include:: views_params.txt
340    """
341    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
342   
343    if not hasattr(obj, "get_attached_documents"):
344        # TODO
345        raise TypeError()
346    if request.method == "POST":
347        formset = get_doc_cad_formset(obj, request.POST)
348        if formset.is_valid():
349            obj.update_doc_cad(formset)
350            return HttpResponseRedirect(".")
351    else:
352        formset = get_doc_cad_formset(obj)
353    archive_form = forms.ArchiveForm()
354    ctx.update({'current_page':'doc-cad',
355                'object_doc_cad': obj.get_attached_documents(),
356                'archive_form' : archive_form,
357                'doc_cad_formset': formset})
358    return r2r('DisplayObjectDocCad.htm', ctx, request)
359
360
361##########################################################################################   
362@handle_errors
363def add_doc_cad(request, obj_type, obj_ref, obj_revi):
364    """
365    Manage html page for link creation (:class:`DocumentPartLink` link) between the selected object and some documents or CAD.
366    It computes a context dictionnary based on
367   
368    .. include:: views_params.txt
369    """
370    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
371   
372    if request.POST:
373        add_doc_cad_form = AddDocCadForm(request.POST)
374        if add_doc_cad_form.is_valid():
375            doc_cad_obj = get_obj_from_form(add_doc_cad_form, request.user)
376            obj.attach_to_document(doc_cad_obj)
377            return HttpResponseRedirect(obj.plmobject_url + "doc-cad/")
378    else:
379        add_doc_cad_form = AddDocCadForm()
380    ctx.update({'link_creation': True,
381                'add_doc_cad_form': add_doc_cad_form,
382                'attach' : (obj, "attach_doc")})
383    return r2r('DisplayDocCadAdd.htm', ctx, request)
384   
385#############################################################################################
386###      All functions which manage the different html pages specific to documents        ###
387#############################################################################################
388@handle_errors
389def display_related_part(request, obj_type, obj_ref, obj_revi):
390    """
391    Manage html page which displays the related part of (:class:`DocumentPartLink` with) the selected object.
392    It computes a context dictionnary based on
393   
394    .. include:: views_params.txt
395    """
396    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
397   
398    if not hasattr(obj, "get_attached_parts"):
399        # TODO
400        raise TypeError()
401    if request.method == "POST":
402        formset = get_rel_part_formset(obj, request.POST)
403        if formset.is_valid():
404            obj.update_rel_part(formset)
405            return HttpResponseRedirect(".")
406    else:
407        formset = get_rel_part_formset(obj)
408    ctx.update({'current_page':'parts',
409                'object_rel_part': obj.get_attached_parts(),
410                'rel_part_formset': formset})
411    return r2r('DisplayObjectRelPart.htm', ctx, request)
412
413##########################################################################################   
414@handle_errors
415def add_rel_part(request, obj_type, obj_ref, obj_revi):
416    """
417    Manage html page for link creation (:class:`DocumentPartLink` link) between the selected object and some parts.
418    It computes a context dictionnary based on
419   
420    .. include:: views_params.txt
421    """
422    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
423   
424    if request.POST:
425        add_rel_part_form = AddRelPartForm(request.POST)
426        if add_rel_part_form.is_valid():
427            part_obj = get_obj_from_form(add_rel_part_form, request.user)
428            obj.attach_to_part(part_obj)
429            ctx.update({'add_rel_part_form': add_rel_part_form, })
430            return HttpResponseRedirect(obj.plmobject_url + "parts/")
431    else:
432        add_rel_part_form = AddRelPartForm()
433    ctx.update({'link_creation': True,
434                'add_rel_part_form': add_rel_part_form,
435                'attach' : (obj, "attach_part") })
436    return r2r('DisplayRelPartAdd.htm', ctx, request)
437
438##########################################################################################
439@handle_errors
440def display_files(request, obj_type, obj_ref, obj_revi):
441    """
442    Manage html page which displays the files (:class:`DocumentFile`) uploaded in the selected object.
443    It computes a context dictionnary based on
444   
445    .. include:: views_params.txt
446    """
447    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
448
449    if not hasattr(obj, "files"):
450        raise TypeError()
451    if request.method == "POST":
452        formset = get_file_formset(obj, request.POST)
453        if formset.is_valid():
454            obj.update_file(formset)
455            return HttpResponseRedirect(".")
456    else:
457        formset = get_file_formset(obj)
458    archive_form = forms.ArchiveForm()
459    ctx.update({'current_page':'files',
460                'file_formset': formset,
461                'archive_form' : archive_form,
462               })
463    return r2r('DisplayObjectFiles.htm', ctx, request)
464
465##########################################################################################
466@handle_errors(undo="..")
467def add_file(request, obj_type, obj_ref, obj_revi):
468    """
469    Manage html page for the files (:class:`DocumentFile`) addition in the selected object.
470    It computes a context dictionnary based on
471   
472    .. include:: views_params.txt
473    """
474    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
475   
476    if request.method == "POST":
477        add_file_form = AddFileForm(request.POST, request.FILES)
478        if add_file_form.is_valid():
479            obj.add_file(request.FILES["filename"])
480            ctx.update({'add_file_form': add_file_form, })
481            return HttpResponseRedirect(obj.plmobject_url + "files/")
482    else:
483        add_file_form = AddFileForm()
484    ctx.update({ 'add_file_form': add_file_form, })
485    return r2r('DisplayFileAdd.htm', ctx, request)
486
487#############################################################################################
488###    All functions which manage the different html pages specific to part and document  ###
489#############################################################################################
490@handle_errors
491def display_management(request, obj_type, obj_ref, obj_revi):
492    """
493    Manage html page which displays the Users who manage the selected object (:class:`PLMObjectUserLink`).
494    It computes a context dictionnary based on
495   
496    .. include:: views_params.txt
497    """
498    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
499   
500    object_management_list = models.PLMObjectUserLink.objects.filter(plmobject=obj)
501    object_management_list = object_management_list.order_by("role")
502    if not ctx["is_owner"]:
503        link = object_management_list.filter(role="notified", user=request.user)
504        ctx["is_notified"] = bool(link)
505        if link:
506            ctx["remove_notify_link"] = link[0]
507        else:
508            initial = { "type" : "User",
509                        "username" : request.user.username
510                      }
511            form = SelectUserForm(initial=initial)
512            for field in ("type", "username"):
513                form.fields[field].widget = HiddenInput()
514            ctx["notify_self_form"] = form
515    ctx.update({'current_page':'management',
516                'object_management': object_management_list})
517   
518    return r2r('DisplayObjectManagement.htm', ctx, request)
519
520##########################################################################################
521@handle_errors(undo="../..")
522def replace_management(request, obj_type, obj_ref, obj_revi, link_id):
523    """
524    Manage html page for the modification of the Users who manage the selected object (:class:`PLMObjectUserLink`).
525    It computes a context dictionnary based on
526   
527    .. include:: views_params.txt
528    :param link_id: :attr:`.PLMObjectUserLink.id`
529    :type link_id: str
530    """
531    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
532    link = models.PLMObjectUserLink.objects.get(id=int(link_id))
533    if obj.object.id != link.plmobject.id:
534        raise ValueError("Bad link id")
535   
536    if request.method == "POST":
537        replace_management_form = SelectUserForm(request.POST)
538        if replace_management_form.is_valid():
539            if replace_management_form.cleaned_data["type"] == "User":
540                user_obj = get_obj_from_form(replace_management_form, request.user)
541                obj.set_role(user_obj.object, link.role)
542                if link.role == 'notified':
543                    obj.remove_notified(link.user)
544            return HttpResponseRedirect("../..")
545    else:
546        replace_management_form = SelectUserForm()
547   
548    ctx.update({'current_page':'management',
549                'replace_management_form': replace_management_form,
550                'link_creation': True,
551                'attach' : (obj, "delegate")})
552    return r2r('DisplayObjectManagementReplace.htm', ctx, request)
553
554##########################################################################################   
555@handle_errors(undo="../..")
556def add_management(request, obj_type, obj_ref, obj_revi):
557    """
558    Manage html page for the addition of a "notification" link
559    (:class:`PLMObjectUserLink`) between some Users and the selected object.
560    It computes a context dictionnary based on
561   
562    .. include:: views_params.txt
563    """
564    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
565   
566    if request.method == "POST":
567        add_management_form = SelectUserForm(request.POST)
568        if add_management_form.is_valid():
569            if add_management_form.cleaned_data["type"] == "User":
570                user_obj = get_obj_from_form(add_management_form, request.user)
571                obj.set_role(user_obj.object, "notified")
572            return HttpResponseRedirect("..")
573    else:
574        add_management_form = SelectUserForm()
575   
576    ctx.update({'current_page':'management',
577                'replace_management_form': add_management_form,
578                'link_creation': True,
579                "attach" : (obj, "delegate")})
580    return r2r('DisplayObjectManagementReplace.htm', ctx, request)
581
582##########################################################################################   
583@handle_errors
584def delete_management(request, obj_type, obj_ref, obj_revi):
585    """
586    Manage html page for the deletion of a "notification" link (:class:`PLMObjectUserLink`) between some Users and the selected object.
587    It computes a context dictionnary based on
588   
589    .. include:: views_params.txt
590    """
591    obj = get_obj(obj_type, obj_ref, obj_revi, request.user)
592    if request.method == "POST":
593        try:
594            link_id = request.POST["link_id"]
595            link = models.PLMObjectUserLink.objects.get(id=int(link_id))
596            obj.remove_notified(link.user)
597        except (KeyError, ValueError, ControllerError):
598            return HttpResponseForbidden()
599    return HttpResponseRedirect("../")
600
601##########################################################################################
602###    Manage html pages for part / document creation and modification                 ###
603##########################################################################################
604
605@handle_errors
606def create_object(request):
607    """
608    Manage html page for the creation of an instance of `models.PLMObject` subclass.
609    It computes a context dictionnary based on
610   
611    :param request: :class:`django.http.QueryDict`
612    :return: a :class:`django.http.HttpResponse`
613    """
614
615    obj, ctx = get_generic_data(request)
616
617    if request.method == 'GET':
618        type_form = TypeFormWithoutUser(request.GET)
619        if type_form.is_valid():
620            type_ = type_form.cleaned_data["type"]
621            cls = models.get_all_plmobjects()[type_]
622            creation_form = get_creation_form(request.user, cls)
623    elif request.method == 'POST':
624        type_form = TypeFormWithoutUser(request.POST)
625        if type_form.is_valid():
626            type_name = type_form.cleaned_data["type"]
627            cls = models.get_all_plmobjects()[type_name]
628            creation_form = get_creation_form(request.user, cls, request.POST)
629            if creation_form.is_valid():
630                user = request.user
631                controller_cls = get_controller(type_name)
632                controller = controller_cls.create_from_form(creation_form, user)
633                return HttpResponseRedirect(controller.plmobject_url)
634    ctx.update({
635        'creation_form': creation_form,
636        'object_type': type_form.cleaned_data["type"],
637    })
638    return r2r('DisplayObject4creation.htm', ctx, request)
639
640##########################################################################################
641@handle_errors(undo="../attributes/")
642def modify_object(request, obj_type, obj_ref, obj_revi):
643    """
644    Manage html page for the modification of the selected object.
645    It computes a context dictionnary based on
646   
647    .. include:: views_params.txt
648    """
649    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
650    cls = models.get_all_plmobjects()[obj_type]
651    if request.method == 'POST' and request.POST:
652        modification_form = get_modification_form(cls, request.POST)
653        if modification_form.is_valid():
654            obj.update_from_form(modification_form)
655            return HttpResponseRedirect(obj.plmobject_url)
656    else:
657        modification_form = get_modification_form(cls, instance=obj.object)
658   
659    ctx['modification_form'] = modification_form
660    return r2r('DisplayObject4modification.htm', ctx, request)
661
662#############################################################################################
663###         All functions which manage the different html pages specific to user          ###
664#############################################################################################
665@handle_errors
666def modify_user(request, obj_ref):
667    """
668    Manage html page for the modification of the selected
669    :class:`~django.contrib.auth.models.User`.
670    It computes a context dictionnary based on
671   
672    :param request: :class:`django.http.QueryDict`
673    :param obj_type: :class:`~django.contrib.auth.models.User`
674    :return: a :class:`django.http.HttpResponse`
675    """
676    obj, ctx = get_generic_data(request, "User", obj_ref)
677    if obj.object != request.user:
678        raise PermissionError("You are not the user")
679    class_for_div="ActiveBox4User"
680    if request.method == 'POST' and request.POST:
681        modification_form = OpenPLMUserChangeForm(request.POST)
682        if modification_form.is_valid():
683            obj.update_from_form(modification_form)
684            return HttpResponseRedirect("/user/%s/" % obj.username)
685    else:
686        modification_form = OpenPLMUserChangeForm(instance=obj.object)
687   
688    ctx.update({'class4div': class_for_div, 'modification_form': modification_form})
689    return r2r('DisplayObject4modification.htm', ctx, request)
690   
691##########################################################################################
692@handle_errors
693def change_user_password(request, obj_ref):
694    """
695    Manage html page for the modification of the selected
696    :class:`~django.contrib.auth.models.User` password.
697    It computes a context dictionnary based on
698   
699    :param request: :class:`django.http.QueryDict`
700    :param obj_ref: :attr:`~django.contrib.auth.models.User.username`
701    :return: a :class:`django.http.HttpResponse`
702    """
703    if request.user.username=='test':
704        return HttpResponseRedirect("/user/%s/attributes/" % request.user)
705    obj, ctx = get_generic_data(request, "User", obj_ref)
706    if obj.object != request.user:
707        raise PermissionError("You are not the user")
708
709    if request.method == 'POST' and request.POST:
710        modification_form = PasswordChangeForm(obj, request.POST)
711        if modification_form.is_valid():
712            obj.set_password(modification_form.cleaned_data['new_password2'])
713            obj.save()
714            return HttpResponseRedirect("/user/%s/" % obj.username)
715    else:
716        modification_form = PasswordChangeForm(obj)
717   
718    ctx.update({'class4div': "ActiveBox4User",
719                'modification_form': modification_form})
720    return r2r('DisplayObject4PasswordModification.htm', ctx, request)
721
722#############################################################################################
723@handle_errors
724def display_related_plmobject(request, obj_type, obj_ref, obj_revi):
725    """
726    Manage html page which displays the related parts and related documents of (:class:`PLMObjectUserLink` with) the selected :class:`~django.contrib.auth.models.User`.
727    It computes a context dictionnary based on
728   
729    .. include:: views_params.txt
730    """
731    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
732   
733    if not hasattr(obj, "get_object_user_links"):
734        # TODO
735        raise TypeError()
736    ctx.update({'current_page':'parts-doc-cad',
737                'object_user_link': obj.get_object_user_links()})
738   
739    return r2r('DisplayObjectRelPLMObject.htm', ctx, request)
740
741#############################################################################################
742@handle_errors
743def display_delegation(request, obj_ref):
744    """
745    Manage html page which displays the delegations of the selected
746    :class:`~django.contrib.auth.models.User`.
747    It computes a context dictionnary based on
748   
749    :param request: :class:`django.http.QueryDict`
750    :param obj_ref: :attr:`~django.contrib.auth.models.User.username`
751    :type obj_ref: str
752    :return: a :class:`django.http.HttpResponse`
753    """
754    obj, ctx = get_generic_data(request, "User", obj_ref)
755   
756    if not hasattr(obj, "get_user_delegation_links"):
757        # TODO
758        raise TypeError()
759    if request.method == "POST":
760        selected_link_id = request.POST.get('link_id')
761        obj.remove_delegation(models.DelegationLink.objects.get(pk=int(selected_link_id)))
762    ctx.update({'current_page':'delegation',
763                'user_delegation_link': obj.get_user_delegation_links()})
764   
765    return r2r('DisplayObjectDelegation.htm', ctx, request)
766
767
768##########################################################################################   
769@handle_errors(undo="../../..")
770def delegate(request, obj_ref, role, sign_level):
771    """
772    Manage html page for delegations modification of the selected
773    :class:`~django.contrib.auth.models.User`.
774    It computes a context dictionnary based on
775   
776    :param request: :class:`django.http.QueryDict`
777    :param obj_type: :class:`~django.contrib.auth.models.User`
778    :type obj_ref: str
779    :param role: :attr:`.DelegationLink.role` if role is not "sign"
780    :type role: str
781    :param sign_level: used for :attr:`.DelegationLink.role` if role is "sign"
782    :type sign_level: str
783    :return: a :class:`django.http.HttpResponse`
784    """
785    obj, ctx = get_generic_data(request, "User", obj_ref)
786   
787    if request.method == "POST":
788        delegation_form = SelectUserForm(request.POST)
789        if delegation_form.is_valid():
790            if delegation_form.cleaned_data["type"] == "User":
791                user_obj = get_obj_from_form(delegation_form, request.user)
792                if role == "notified" or role == "owner":
793                    obj.delegate(user_obj.object, role)
794                    return HttpResponseRedirect("../..")
795                elif role == "sign":
796                    if sign_level == "all":
797                        obj.delegate(user_obj.object, "sign*")
798                        return HttpResponseRedirect("../../..")
799                    elif sign_level.isdigit():
800                        obj.delegate(user_obj.object, level_to_sign_str(int(sign_level)-1))
801                        return HttpResponseRedirect("../../..")
802    else:
803        delegation_form = SelectUserForm()
804    if role == 'sign':
805        if sign_level.isdigit():
806            role = _("signer level") + " " + str(sign_level)
807        else:
808            role = _("signer all levels")
809    elif role == "notified":
810        role = _("notified")
811   
812    ctx.update({'current_page':'delegation',
813                'replace_management_form': delegation_form,
814                'link_creation': True,
815                'attach' : (obj, "delegate"),
816                'role': role})
817    return r2r('DisplayObjectManagementReplace.htm', ctx, request)
818   
819   
820##########################################################################################
821###             Manage html pages for file check-in / check-out / download             ###
822##########################################################################################   
823@handle_errors
824def checkin_file(request, obj_type, obj_ref, obj_revi, file_id_value):
825    """
826    Manage html page for the files (:class:`DocumentFile`) checkin in the selected object.
827    It computes a context dictionnary based on
828   
829    .. include:: views_params.txt
830    :param file_id_value: :attr:`.DocumentFile.id`
831    :type file_id_value: str
832    :return: a :class:`django.http.HttpResponse`
833    """
834    obj, ctx = get_generic_data(request, obj_type, obj_ref, obj_revi)
835    if request.POST:
836        checkin_file_form = AddFileForm(request.POST, request.FILES)
837        if checkin_file_form.is_valid():
838            obj.checkin(models.DocumentFile.objects.get(id=file_id_value),
839                        request.FILES["filename"])
840            return HttpResponseRedirect(obj.plmobject_url + "files/")
841    else:
842        checkin_file_form = AddFileForm()
843    ctx['add_file_form'] =  checkin_file_form
844    return r2r('DisplayFileAdd.htm', ctx, request)
845
846##########################################################################################
847@handle_errors
848def download(request, docfile_id, filename=""):
849    """
850    View to download a document file.
851   
852    :param request: :class:`django.http.QueryDict`
853    :param docfile_id: :attr:`.DocumentFile.id`
854    :type docfile_id: str
855    :return: a :class:`django.http.HttpResponse`
856    """
857    doc_file = models.DocumentFile.objects.get(id=docfile_id)
858    ctrl = get_obj_by_id(int(doc_file.document.id), request.user)
859    ctrl.check_readable()
860    name = doc_file.filename.encode("utf-8", "ignore")
861    mimetype = guess_type(name, False)[0]
862    if not mimetype:
863        mimetype = 'application/octet-stream'
864    response = HttpResponse(file(doc_file.file.path), mimetype=mimetype)
865    response["Content-Length"] = doc_file.file.size
866    if not filename:
867        response['Content-Disposition'] = 'attachment; filename="%s"' % name
868    return response
869
870@handle_errors
871def download_archive(request, obj_type, obj_ref, obj_revi):
872    """
873    View to download all files from a document/part.
874
875    .. include:: views_params.txt
876    """
877
878    obj = get_obj(obj_type, obj_ref, obj_revi, request.user)
879    obj.check_readable()
880   
881    d_o_u = "document__owner__username"
882    if obj.is_document:
883        files = obj.files.select_related(d_o_u)
884    elif obj.is_part:
885        links = obj.get_attached_documents()
886        docs = (link.document for link in links)
887        files = itertools.chain(*(doc.files.select_related(d_o_u)
888            for doc in docs))
889    else:
890        return HttpResponseForbidden()
891
892    form = forms.ArchiveForm(request.GET)
893    if form.is_valid():
894        format = form.cleaned_data["format"]
895        name = "%s_%s.%s" % (obj_ref, obj_revi, format)
896        mimetype = guess_type(name, False)[0]
897        if not mimetype:
898            mimetype = 'application/octet-stream'
899        content = generate_archive(files, format)
900        response = HttpResponse(content, mimetype=mimetype)
901        #response["Content-Length"] = size
902        response['Content-Disposition'] = 'attachment; filename="%s"' % name
903        return response
904    return HttpResponseForbidden()
905
906##########################################################################################
907@handle_errors
908def checkout_file(request, obj_type, obj_ref, obj_revi, docfile_id):
909    """
910    Manage html page for the files (:class:`DocumentFile`) checkout from the selected object.
911    It locks the :class:`DocumentFile` and, after, calls :func:`.views.download`
912   
913    .. include:: views_params.txt
914    :param docfile_id: :attr:`.DocumentFile.id`
915    :type docfile_id_value: str
916    """
917    obj = get_obj(obj_type, obj_ref, obj_revi, request.user)
918    doc_file = models.DocumentFile.objects.get(id=docfile_id)
919    obj.lock(doc_file)
920    return download(request, docfile_id)
921
922##########################################################################################
923###                     Manage html pages for navigate function                        ###
924##########################################################################################   
925@handle_errors
926def navigate(request, obj_type, obj_ref, obj_revi):
927    """
928    Manage html page which displays a graphical picture the different links
929    between :class:`~django.contrib.auth.models.User` and  :class:`.models.PLMObject`.
930    This function uses Graphviz (http://graphviz.org/).
931    Some filters let user defines which type of links he/she wants to display.
932    It computes a context dictionary based on
933   
934    .. include:: views_params.txt
935    """
936    ctx = get_navigate_data(request, obj_type, obj_ref, obj_revi)
937    return r2r('Navigate.htm', ctx, request)
938
939@handle_errors
940def display_users(request, obj_ref):
941    obj, ctx = get_generic_data(request, "Group", obj_ref)
942    if request.method == "POST":
943        formset = forms.get_user_formset(obj, request.POST)
944        if formset.is_valid():
945            obj.update_users(formset)
946            return HttpResponseRedirect(".")
947    else:
948        formset = forms.get_user_formset(obj)
949    ctx["user_formset"] = formset
950    ctx["pending_invitations"] = obj.invitation_set.filter(
951            state=models.Invitation.PENDING)
952    ctx['current_page'] = 'users'
953    ctx['in_group'] = bool(request.user.groups.filter(id=obj.id))
954    return r2r("groups/users.htm", ctx, request)
955
956@handle_errors
957def group_add_user(request, obj_ref):
958    """
959    View of the *Add user* page of a group.
960
961    """
962
963    obj, ctx = get_generic_data(request, "Group", obj_ref)
964    if request.method == "POST":
965        form = SelectUserForm(request.POST)
966        if form.is_valid():
967            obj.add_user(User.objects.get(username=form.cleaned_data["username"]))
968            return HttpResponseRedirect("..")
969    else:
970        form = forms.SelectUserForm()
971    ctx["add_user_form"] = form
972    ctx['current_page'] = 'users'
973    return r2r("groups/add_user.htm", ctx, request)
974
975@handle_errors
976def group_ask_to_join(request, obj_ref):
977    obj, ctx = get_generic_data(request, "Group", obj_ref)
978    if request.method == "POST":
979        obj.ask_to_join()
980        return HttpResponseRedirect("..")
981    else:
982        form = forms.SelectUserForm()
983    ctx["ask_form"] = ""
984    ctx['current_page'] = 'users'
985    ctx['in_group'] = bool(request.user.groups.filter(id=obj.id))
986    return r2r("groups/ask_to_join.htm", ctx, request)
987
988@handle_errors
989def display_groups(request, obj_ref):
990    """
991    View of the *groups* page of an user.
992
993    """
994
995    obj, ctx = get_generic_data(request, "User", obj_ref)
996    ctx['current_page'] = 'groups'
997    return r2r("users/groups.htm", ctx, request)
998
999@handle_errors
1000def sponsor(request, obj_ref):
1001    obj, ctx = get_generic_data(request, "User", obj_ref)
1002    if request.method == "POST":
1003        form = forms.SponsorForm(request.POST)
1004        if form.is_valid():
1005            new_user = form.save()
1006            obj.sponsor(new_user)
1007            return HttpResponseRedirect("..")
1008    else:
1009        form = SponsorForm(initial={"sponsor":obj.id}, sponsor=obj.id)
1010    ctx["sponsor_form"] = form
1011    ctx['current_page'] = 'delegation'
1012    return r2r("users/sponsor.htm", ctx, request)
1013
1014@handle_errors
1015def display_plmobjects(request, obj_ref):
1016    """
1017    View of the *objects* page of a group.
1018    """
1019   
1020    obj, ctx = get_generic_data(request, "Group", obj_ref)
1021    ctx["objects"] = obj.plmobject_group.all().order_by("type", "reference", "revision")
1022    ctx['current_page'] = 'groups'
1023    return r2r("groups/objects.htm", ctx, request)
1024
1025@handle_errors(undo="../../../users/")
1026def accept_invitation(request, obj_ref, token):
1027    token = long(token)
1028    obj, ctx = get_generic_data(request, "Group", obj_ref)
1029    inv = models.Invitation.objects.get(token=token)
1030    if request.method == "POST":
1031        form = forms.InvitationForm(request.POST)
1032        if form.is_valid() and inv == form.cleaned_data["invitation"]:
1033            obj.accept_invitation(inv)
1034            return HttpResponseRedirect("../../../users/")
1035    else:
1036        form = forms.InvitationForm(initial={"invitation" : inv})
1037    ctx["invitation_form"] = form
1038    ctx['current_page'] = 'users'
1039    ctx["invitation"] = inv
1040    return r2r("groups/accept_invitation.htm", ctx, request)
1041
1042 
1043@handle_errors(undo="../../../users/")
1044def refuse_invitation(request, obj_ref, token):
1045    token = long(token)
1046    obj, ctx = get_generic_data(request, "Group", obj_ref)
1047    inv = models.Invitation.objects.get(token=token)
1048    if request.method == "POST":
1049        form = forms.InvitationForm(request.POST)
1050        if form.is_valid() and inv == form.cleaned_data["invitation"]:
1051            obj.refuse_invitation(inv)
1052            return HttpResponseRedirect("../../../users/")
1053    else:
1054        form = forms.InvitationForm(initial={"invitation" : inv})
1055    ctx["invitation_form"] = form
1056    ctx["invitation"] = inv
1057    ctx['current_page'] = 'users'
1058    return r2r("groups/refuse_invitation.htm", ctx, request)
1059
1060@handle_errors(undo="../..")
1061def import_csv_init(request, target="csv"):
1062    obj, ctx = get_generic_data(request)
1063    if request.method == "POST":
1064        csv_form = CSVForm(request.POST, request.FILES)
1065        if csv_form.is_valid():
1066            f = request.FILES["file"]
1067            prefix = "openplmcsv" + request.user.username
1068            tmp = tempfile.NamedTemporaryFile(prefix=prefix, delete=False)
1069            for chunk in f.chunks():
1070                tmp.write(chunk)
1071            name = os.path.split(tmp.name)[1][len(prefix):]
1072            tmp.close()
1073            encoding = csv_form.cleaned_data["encoding"]
1074            return HttpResponseRedirect("/import/%s/%s/%s/" % (target, name,
1075                                        encoding))
1076    else:
1077        csv_form = CSVForm()
1078    ctx["csv_form"] = csv_form
1079    ctx["step"] = 1
1080    ctx["target"] = target
1081    return r2r("import/csv.htm", ctx, request)
1082
1083@handle_errors(undo="../..")
1084def import_csv_apply(request, target, filename, encoding):
1085    obj, ctx = get_generic_data(request)
1086    ctx["encoding_error"] = False
1087    ctx["io_error"] = False
1088    Importer = csvimport.IMPORTERS[target]
1089    Formset = forms.get_headers_formset(Importer)
1090    try:
1091        path = os.path.join(tempfile.gettempdir(),
1092                            "openplmcsv" + request.user.username + filename)
1093        with open(path, "rb") as csv_file:
1094            importer = Importer(csv_file, request.user, encoding)
1095            preview = importer.get_preview()
1096        if request.method == "POST":
1097            headers_formset = Formset(request.POST)
1098            if headers_formset.is_valid():
1099                headers = headers_formset.headers
1100                try:
1101                    with open(path, "rb") as csv_file:
1102                        importer = Importer(csv_file, request.user, encoding)
1103                        importer.import_csv(headers)
1104                except csvimport.CSVImportError as exc:
1105                    ctx["errors"] = exc.errors.iteritems()
1106                else:
1107                    os.remove(path)
1108                    return HttpResponseRedirect("/import/done/")
1109        else:
1110            initial = [{"header": header} for header in preview.guessed_headers]
1111            headers_formset = Formset(initial=initial)
1112        ctx.update({
1113            "preview" :  preview,
1114            "preview_data" : itertools.izip((f["header"] for f in headers_formset.forms),
1115                preview.headers, *preview.rows),
1116            "headers_formset" : headers_formset,
1117        })
1118    except UnicodeError:
1119        ctx["encoding_error"] = True
1120    except (IOError, csv.Error):
1121        ctx["io_error"] = True
1122    ctx["has_critical_error"] = ctx["io_error"] or ctx["encoding_error"] \
1123            or "errors" in ctx
1124    ctx["csv_form"] = CSVForm(initial={"encoding" : encoding})
1125    ctx["step"] = 2
1126    ctx["target"] = target
1127    return r2r("import/csv.htm", ctx, request)
1128
1129
1130@handle_errors
1131def import_csv_done(request):
1132    obj, ctx = get_generic_data(request)
1133    return r2r("import/done.htm", ctx, request)
1134
Note: See TracBrowser for help on using the repository browser.