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

Revision 595, 44.5 KB checked in by pcosquer, 8 years ago (diff)

3D branch: merge changes from trunk rev 594

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