1- from typing import Type
1+ import discord
22
3- from core import Plugin , PluginInstallationError
4- from plugins .voting .listener import VotingListener
3+ from core import Plugin , PluginInstallationError , Group , utils , get_translation , Server , Status
4+ from discord import app_commands , SelectOption
5+ from plugins .creditsystem .commands import CreditSystem
56from services .bot import DCSServerBot
7+ from typing import Type , Literal , cast
8+
9+ from .base import VotableItem
10+ from .listener import VotingListener , VotingHandler
11+
12+ _ = get_translation (__name__ .split ('.' )[1 ])
613
714
815class Voting (Plugin [VotingListener ]):
@@ -11,6 +18,149 @@ def __init__(self, bot: DCSServerBot, eventlistener: Type[VotingListener] = None
1118 if not self .locals :
1219 raise PluginInstallationError (reason = f"No { self .plugin_name } .yaml file found!" , plugin = self .plugin_name )
1320
21+ # New command group "/vote"
22+ vote = Group (name = "vote" , description = _ ("Commands to manage votes" ))
23+
24+ @vote .command (name = 'list' , description = _ ('Lists the current votes' ))
25+ @app_commands .guild_only ()
26+ @utils .app_has_role ('DCS' )
27+ async def _list (self , interaction : discord .Interaction ):
28+ servers = []
29+ votes = []
30+ voters = []
31+ for server_name , handler in self .eventlistener ._all_votes .items ():
32+ servers .append (server_name )
33+ votes .append (repr (handler .item ))
34+ voters .append (str (len (handler .votes )))
35+ if len (servers ):
36+ embed = discord .Embed (color = discord .Color .blue ())
37+ embed .add_field (name = _ ("Server" ), value = '\n ' .join (servers ))
38+ embed .add_field (name = _ ("Running Vote" ), value = '\n ' .join (votes ))
39+ embed .add_field (name = _ ("Voters" ), value = '\n ' .join (voters ))
40+ # noinspection PyUnresolvedReferences
41+ await interaction .response .send_message (embed = embed , ephemeral = True )
42+ else :
43+ # noinspection PyUnresolvedReferences
44+ await interaction .response .send_message (_ ("No running votes found." ), ephemeral = True )
45+
46+ @vote .command (description = _ ('Create a vote' ))
47+ @app_commands .guild_only ()
48+ @utils .app_has_role ('DCS' )
49+ async def create (self , interaction : discord .Interaction ,
50+ server : app_commands .Transform [Server , utils .ServerTransformer (status = [Status .RUNNING ])],
51+ what : Literal ['Restart' , 'Mission Change' , 'Weather Change' ]):
52+ config = self .get_config (server )
53+ # Users with either the "creator" role or "DCS Admin" can use this command
54+ roles = set (config .get ('creator' , []) + self .bot .roles ['DCS Admin' ])
55+ if not utils .check_roles (roles , interaction .user ):
56+ # noinspection PyUnresolvedReferences
57+ await interaction .response .send_message (_ ("You are not authorized to create a vote." ))
58+ return
59+ is_admin = utils .check_roles (self .bot .roles ['DCS Admin' ], interaction .user )
60+
61+ points = config .get ('credits' )
62+ credits = campaign_id = ucid = None
63+ if not is_admin and points :
64+ ucid = await self .bot .get_ucid_by_member (interaction .user )
65+ if not ucid :
66+ _mission = self .bot .cogs ['Mission' ]
67+ # noinspection PyUnresolvedReferences
68+ await interaction .response .send_message (_ ("Use {} to link your account." ).format (
69+ (await utils .get_command (self .bot , name = _mission .linkme .name )).mention
70+ ), ephemeral = True )
71+ return
72+ _creditssystem = cast (CreditSystem , self .bot .cogs ['CreditSystem' ])
73+ data = await _creditssystem .get_credits (ucid )
74+ campaign_id , campaign_name = utils .get_running_campaign (self .node , server )
75+ credits = next ((x ['credits' ] for x in data if x ['id' ] == campaign_id ), 0 )
76+ if credits < points :
77+ # noinspection PyUnresolvedReferences
78+ await interaction .response .send_message (
79+ _ ("You don't have enough credits to create a vote!" ), ephemeral = True )
80+ return
81+
82+ if self .eventlistener ._all_votes .get (server .name ):
83+ # noinspection PyUnresolvedReferences
84+ await interaction .response .send_message (_ ('There is already a voting running on this server.' ),
85+ ephemeral = True )
86+ return
87+
88+ if what == 'Mission Change' and config ['options' ].get ('mission' ) is not None :
89+ message = _ ("Vote for a mission change on server {}" ).format (server .name )
90+ element = 'mission'
91+ elif what == 'Restart' and config ['options' ].get ('restart' ) is not None :
92+ message = _ ("Vote for a restart of server {}" ).format (server .name )
93+ element = 'restart'
94+ elif what == 'Weather Change' and config ['options' ].get ('preset' ) is not None :
95+ message = _ ("Vote for a weather change on server {}" ).format (server .name )
96+ element = 'preset'
97+ else :
98+ # noinspection PyUnresolvedReferences
99+ await interaction .response .send_message (_ ("Unknown vote type or vote type not configured." ), ephemeral = True )
100+ return
101+
102+ if not is_admin and points :
103+ message += "\n _" + _ ("This vote will cost you {} credits." ).format (points ) + "_"
104+
105+ if not await utils .yn_question (interaction , question = _ ("Do you want to create a vote?" ), message = message ):
106+ await interaction .followup .send (_ ('Aborted.' ))
107+ return
108+
109+ class_name = f"plugins.voting.options.{ element } .{ element .title ()} "
110+ item : VotableItem = utils .str_to_class (class_name )(
111+ server , config ['options' ].get (element )
112+ )
113+ choices = await item .get_choices ()
114+ if len (choices ) > 2 :
115+ rc = await utils .selection (interaction ,
116+ title = _ ("Active players can vote for any of these options.\n "
117+ "Make your vote now!" ),
118+ options = [
119+ SelectOption (label = x , value = str (idx + 2 ))
120+ for idx , x in enumerate (choices [1 :])
121+ if idx < 25
122+ ])
123+ if rc is None :
124+ await interaction .followup .send (_ ("Aborted." ))
125+ return
126+ vote = int (rc )
127+ else :
128+ vote = 2
129+
130+ if not item .can_vote ():
131+ await interaction .followup .send (_ ('This option is not available at the moment.' ), ephemeral = True )
132+
133+ handler = VotingHandler (listener = self .eventlistener , item = item , server = server , config = config )
134+ self .eventlistener ._all_votes [server .name ] = handler
135+ handler .votes [vote ] = 1
136+
137+ await interaction .followup .send (_ ('{} created. It is open for {}' ).format (
138+ repr (item ), utils .format_time (config .get ('time' , 300 ))))
139+
140+ if not is_admin and points :
141+ async with self .apool .connection () as conn :
142+ await conn .execute ("""
143+ UPDATE credits SET points = %s WHERE campaign_id = %s AND player_ucid = %s
144+ """ , (credits - points , campaign_id , ucid ))
145+ await conn .execute ("""
146+ INSERT INTO credits_log (campaign_id, event, player_ucid, old_points, new_points, remark)
147+ VALUES (%s, %s, %s, %s, %s, %s)
148+ """ , (campaign_id , 'vote' , ucid , credits , credits - points , _ ("Paid for a vote" )))
149+
150+ @vote .command (description = _ ('Cancel a vote' ))
151+ @app_commands .guild_only ()
152+ @utils .app_has_role ('DCS Admin' )
153+ async def cancel (self , interaction : discord .Interaction ,
154+ server : app_commands .Transform [Server , utils .ServerTransformer (status = [Status .RUNNING ])]):
155+ handler = self .eventlistener ._all_votes .get (server .name )
156+ if not handler :
157+ # noinspection PyUnresolvedReferences
158+ await interaction .response .send_message (_ ('There is no voting running on this server.' ), ephemeral = True )
159+ return
160+ handler .cancel ()
161+ # noinspection PyUnresolvedReferences
162+ await interaction .response .send_message (_ ('Voting cancelled.' ), ephemeral = utils .get_ephemeral (interaction ))
163+
14164
15165async def setup (bot : DCSServerBot ):
16166 await bot .add_cog (Voting (bot , VotingListener ))
0 commit comments